home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 23 / CU Amiga - Super CD-ROM 23 (June 1998).iso / CUCD / Sound / PlayMF_VU / Fireworks / Source / fireworks.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-22  |  90.5 KB  |  4,115 lines

  1.  
  2. /*-------------------------------------------------*/
  3. /* fireworks.c - graphical MIDI note visualisation */
  4. /*          ® 1998 by Christian Buchner            */
  5. /*-------------------------------------------------*/
  6.  
  7. #define FPS 25                /* nominal frames per seconds */
  8. #define MIN_FPS 2            /* when FPS drops below, the */
  9.                             /* watchdog timer intervenes */
  10.  
  11. #define NORMPRI -10            /* priority during normal operation */
  12. #define HIGHPRI  10            /* priority in idle mode or when */
  13.                             /* watchdog timer intervenes */
  14.  
  15. #define MAXCOORD 1024
  16.  
  17. #define CENTER_X 512        /* window width  is 0...MAXCOORD */
  18. #define CENTER_Y 980        /* window height is 0...MAXCOORD */
  19.  
  20.  
  21.  
  22. /* Library bases */
  23.  
  24. struct ExecBase            *SysBase;
  25. struct DosLibrary        *DOSBase;
  26. struct GfxBase            *GfxBase;
  27. struct Library            *LayersBase;
  28. struct IntuitionBase    *IntuitionBase;
  29. struct Library             *GadToolsBase;
  30. struct Library            *UtilityBase;
  31. struct Library            *DatatypesBase;
  32. struct Library            *AslBase;
  33. struct Library            *WorkbenchBase;
  34. struct Library            *CamdBase;
  35. struct Library            *TimerBase;
  36. BOOL                     FPBase;    /* pseudo floating point base */
  37.  
  38.  
  39. /* Workbench or not? */
  40.  
  41. BOOL WBMode = FALSE;
  42.  
  43.  
  44. /* this task */
  45.  
  46. struct Task *MyTask;
  47.  
  48.  
  49. /* these flags serve for keeping track of asynchronous tasks */
  50.  
  51. typedef enum
  52. {
  53.     AboutTask  = 0x00000001,    /* these are the asynchronous messages */
  54.     SaveTask   = 0x00000002,
  55.     ErrTask    = 0x00000004,
  56.     DropTask   = 0x00000008,
  57.     LaunchTask = 0x00000010,
  58.     CloseTask  = 0x00000020,
  59.     
  60.     PlayTask   = 0x00000100,    /* these are the file requesters */
  61.     ImageTask  = 0x00000200,
  62.     
  63.     ScreenTask = 0x00001000,    /* the screenmode requester */
  64.  
  65. } TaskFlag;
  66.  
  67.  
  68. /* Function Prototypes */
  69.  
  70. LONG ShellInterface(void);
  71. LONG WBInterface(struct Process *MyProc);
  72.  
  73. BOOL WindowLayout(struct Globals *glob, WORD *minw, WORD *minh, WORD *maxw, WORD *maxh);
  74.  
  75. LONG Fireworks(struct Prefs *pref);
  76. void MainLoop(struct Globals *glob, struct Prefs *pref);
  77.  
  78. APTR Lin_InitFireworks(struct Globals *glob, struct Prefs *pref);
  79. void Lin_RethinkWindow(APTR data);
  80. void Lin_TimePassed(APTR data);
  81. BOOL Lin_IsIdle(APTR data);
  82. void Lin_DrawFireworks(APTR data, UWORD Mask);
  83. void Lin_NoteOn(APTR data, UBYTE chn, UBYTE note, UBYTE vel);
  84. void Lin_NoteOff(APTR data, UBYTE chn, UBYTE note);
  85. void Lin_ReleaseNotes(APTR data);
  86. void Lin_FreeNoteData(APTR data);
  87. void Lin_ExitFireworks(APTR data);
  88.  
  89. APTR Par_InitFireworks(struct Globals *glob, struct Prefs *pref);
  90. void Par_RethinkWindow(APTR data);
  91. void Par_TimePassed(APTR data);
  92. BOOL Par_IsIdle(APTR data);
  93. void Par_DrawFireworks(APTR data, UWORD Mask);
  94. void Par_NoteOn(APTR data, UBYTE chn, UBYTE note, UBYTE vel);
  95. void Par_NoteOff(APTR data, UBYTE chn, UBYTE note);
  96. void Par_ReleaseNotes(APTR data);
  97. void Par_FreeNoteData(APTR data);
  98. void Par_ExitFireworks(APTR data);
  99.  
  100. void Par_DrawFireworks2(APTR data, UWORD Mask);
  101.  
  102. BOOL OpenGUI(struct Globals *glob, struct Prefs *pref);
  103. void TitleWindow(struct Globals *glob, UBYTE *Text, ...);
  104. BOOL SelectScreenMode(struct Globals *glob, struct Prefs *pref, struct ScreenModeRequester **srq);
  105. void CloseGUI(struct Globals *glob, struct Prefs *pref);
  106.  
  107. void InitPrefs(struct Prefs *pref);
  108. void InitGlobals(struct Globals *glob);
  109.  
  110. int __interrupt __saveds VBlankInterface( void );
  111.  
  112. void AsyncSelectScreenMode(struct Globals *glob, struct Prefs *pref);
  113. void AsyncSelectImage(struct Globals *glob, struct Prefs *pref);
  114. void AsyncSelectAndPlay(struct Globals *glob, struct Prefs *pref);
  115.  
  116. BOOL InitOrUpdateGraphics(struct Globals *glob, struct Prefs *pref);
  117. void FreeGraphics(struct Globals *glob);
  118. struct Screen *GetScreen(struct Globals *glob);
  119.  
  120. void LoadImage(struct Globals *glob, struct Prefs *pref);
  121. BOOL SelectImage(struct Globals *glob, struct FileRequester **fr, UBYTE *filebuffer, ULONG MaxSize);
  122.  
  123. BOOL SelectMIDI(struct Globals *glob, struct FileRequester **fr, UBYTE *filebuffer, ULONG MaxSize);
  124. void PlayMIDI(struct Globals *glob, struct Prefs *pref);
  125. void StopMIDI(struct Globals *glob, struct Prefs *pref);
  126.  
  127. BOOL OpenLibs(void);
  128. void CloseLibs(void);
  129.  
  130. struct timerequest *OpenTimer(void);
  131. void CloseTimer(struct timerequest *treq);
  132. ULONG GetTimeDelta(void);
  133.  
  134. BOOL AllocAsync(struct Globals *glob, TaskFlag flg);
  135. void FreeAsync(struct Globals *glob, TaskFlag flg);
  136. BOOL AskAsync(struct Globals *glob);
  137. void WaitAsync(struct Globals *glob);
  138.  
  139. LONG __stdargs Message(UBYTE *Msg,UBYTE *Options,...);
  140. LONG           MessageA(UBYTE *Msg,UBYTE *Options,APTR Args);
  141. LONG __stdargs AsyncMessage(struct Globals *glob, TaskFlag flg, UBYTE *Msg,UBYTE *Options,...);
  142. void __stdargs _XCEXIT(LONG lcode);
  143.  
  144. extern BOOL __stdargs __fpinit(void);
  145. extern void __stdargs __fpterm(void);
  146.  
  147.                               /* SPrintf.a */
  148. APTR __stdargs SPrintf(char *, const char *, ...);
  149. APTR __stdargs VSPrintf(char *, const char *, va_list);
  150.  
  151.  
  152. /* CAM Library data and protos */
  153.  
  154. struct MidiNode *CreateMidi(Tag tag, ...);
  155. BOOL SetMidiAttrs(struct MidiNode *mi, Tag tag, ...);
  156. struct MidiLink *AddMidiLink(struct MidiNode *mi, LONG type, Tag tag, ...);
  157. BOOL SetMidiLinkAttrs(struct MidiLink *mi, Tag tag, ...);
  158.  
  159.  
  160.  
  161. /* Intuition data structures */
  162.  
  163. enum
  164. {
  165.     Backgroundpen = 0,
  166.     Channelpens = 1,
  167.     
  168.     NUMPENS = Channelpens + 16
  169. };
  170.  
  171.  
  172. ULONG ScreenPalette[] =
  173. {
  174.     ((2L<<16) | 0),
  175.     
  176.     0x00000000, 0x00000000, 0x00000000,
  177.     0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA,
  178.     
  179.     ((0L<<16) | 0)
  180. };
  181.  
  182.  
  183. UWORD PenArray[] =
  184. {
  185.     1, // DETAILPEN
  186.     0, // BLOCKPEN
  187.     1, // TEXTPEN
  188.     1, // SHINEPEN
  189.     1, // SHADOWPEN
  190.     1, // FILLPEN
  191.     0, // FILLTEXTPEN
  192.     0, // BACKGROUNDPEN
  193.     1, // HIGHLIGHTTEXTPEN
  194.     1, // BARDETAILPEN
  195.     0, // BARBLOCKPEN
  196.     0, // BARTRIMPEN
  197. };
  198.  
  199.  
  200. UBYTE PenColors[NUMPENS][3] =
  201. {
  202.     0x00, 0x00, 0x00,            /* Black background */
  203.     
  204.     255,  64,  64,            /* Chan  1 */
  205.     255, 137,  64,            /* Chan  2 */
  206.     255, 207,  64,            /* Chan  3 */
  207.     230, 255,  64,            /* Chan  4 */
  208.     159, 255,  64,            /* Chan  5 */
  209.      86, 255,  64,            /* Chan  6 */
  210.      64, 255, 112,            /* Chan  7 */
  211.      64, 255, 185,            /* Chan  8 */
  212.      64, 255, 255,            /* Chan  9 */
  213.      64, 185, 255,            /* Chan 10 */
  214.      64, 112, 255,            /* Chan 11 */
  215.      86,  64, 255,            /* Chan 12 */
  216.     159,  64, 255,            /* Chan 13 */
  217.     230,  64, 255,            /* Chan 14 */
  218.     255,  64, 207,            /* Chan 15 */
  219.     255,  64, 137,            /* Chan 16 */
  220. };
  221.  
  222.  
  223. static UWORD chip WaitPointer[] =
  224. {
  225.     0x0000, 0x0000,
  226.  
  227.     0x0400, 0x07C0,
  228.     0x0000, 0x07C0,
  229.     0x0100, 0x0380,
  230.     0x0000, 0x07E0,
  231.     0x07C0, 0x1FF8,
  232.     0x1FF0, 0x3FEC,
  233.     0x3FF8, 0x7FDE,
  234.     0x3FF8, 0x7FBE,
  235.     0x7FFC, 0xFF7F,
  236.     0x7EFC, 0xFFFF,
  237.     0x7FFC, 0xFFFF,
  238.     0x3FF8, 0x7FFE,
  239.     0x3FF8, 0x7FFE,
  240.     0x1FF0, 0x3FFC,
  241.     0x07C0, 0x1FF8,
  242.     0x0000, 0x07E0,
  243.  
  244.     0x0000, 0x0000,        /* reserved, must be NULL */
  245. };
  246.  
  247.  
  248. /* global preferences data */
  249.  
  250. struct Prefs
  251. {
  252.     ULONG Flags;
  253.     UWORD WinX;
  254.     UWORD WinY;
  255.     UWORD WinW;
  256.     UWORD WinH;
  257.     UBYTE *Image;
  258.     UBYTE NewImage[240];
  259.     UBYTE *Link;
  260.     UBYTE NewLink[32];
  261.     ULONG ScreenMode;
  262.     UWORD ScreenWidth;
  263.     UWORD ScreenHeight;
  264.     UWORD ScreenDepth;
  265.     ULONG OverscanType;
  266.     BOOL AutoScroll;
  267.     UBYTE MIDIFile[240];
  268.     UWORD FWMode;
  269. };
  270.  
  271. #define PREFF_DOUBLE     1
  272. #define PREFF_TILE       2
  273. #define PREFF_FULLSCREEN 4
  274. #define PREFF_BACKDROP   8
  275.  
  276.  
  277. /* The fireworks modes */
  278.  
  279. enum
  280. {
  281.     LinearMode,
  282.     ParabolicMode,
  283.     ParabolicMode2,
  284.     NUM_FWMODES,
  285. };
  286.  
  287. struct FWDefinition
  288. {
  289.     APTR (*InitFireworks)(struct Globals *glob, struct Prefs *pref);
  290.     void (*RethinkWindow)(APTR data);
  291.     void (*TimePassed)(APTR data);
  292.     BOOL (*IsIdle)(APTR data);
  293.     void (*DrawFireworks)(APTR data, UWORD Mask);
  294.     void (*NoteOn)(APTR data, UBYTE chn, UBYTE note, UBYTE vel);
  295.     void (*NoteOff)(APTR data, UBYTE chn, UBYTE note);
  296.     void (*ReleaseNotes)(APTR data);
  297.     void (*FreeNoteData)(APTR data);
  298.     void (*ExitFireworks)(APTR data);
  299. } FWDefinitions[NUM_FWMODES] =
  300. {
  301.     &Lin_InitFireworks,
  302.     &Lin_RethinkWindow,
  303.     &Lin_TimePassed,
  304.     &Lin_IsIdle,
  305.     &Lin_DrawFireworks,
  306.     &Lin_NoteOn,
  307.     &Lin_NoteOff,
  308.     &Lin_ReleaseNotes,
  309.     &Lin_FreeNoteData,
  310.     &Lin_ExitFireworks,
  311.     
  312.     &Par_InitFireworks,
  313.     &Par_RethinkWindow,
  314.     &Par_TimePassed,
  315.     &Par_IsIdle,
  316.     &Par_DrawFireworks,
  317.     &Par_NoteOn,
  318.     &Par_NoteOff,
  319.     &Par_ReleaseNotes,
  320.     &Par_FreeNoteData,
  321.     &Par_ExitFireworks,
  322.     
  323.     &Par_InitFireworks,
  324.     &Par_RethinkWindow,
  325.     &Par_TimePassed,
  326.     &Par_IsIdle,
  327.     &Par_DrawFireworks2,
  328.     &Par_NoteOn,
  329.     &Par_NoteOff,
  330.     &Par_ReleaseNotes,
  331.     &Par_FreeNoteData,
  332.     &Par_ExitFireworks,
  333. };
  334.  
  335.  
  336. /* all data structures and pointers needed by this program */
  337.  
  338. struct Globals
  339. {
  340.     struct Screen *LockedScreen;
  341.     struct Screen *OpenedScreen;
  342.     
  343.     struct Screen *Screen;
  344.     APTR VisualInfo;
  345.     struct Window *Window;
  346.     struct Menu   *Menu;
  347.     
  348.     struct Window *ProcWindow;
  349.     
  350.     struct AppWindow *AppWindow;
  351.     
  352.     struct timerequest *treq;
  353.     
  354.     WORD ww, wh;
  355.     
  356.     LONG PenArray[NUMPENS];
  357.     
  358.     Object *dto;
  359.     struct BitMap *BGBitMap;
  360.     struct BitMap *PaintBitMap;
  361.     struct RastPort PaintRP;
  362.     struct Layer_Info *LInfo;
  363.     struct Layer *PaintLayer;
  364.     
  365.     struct MidiNode *midi;
  366.     struct MidiLink *link;
  367.     
  368.     UBYTE WTitle[80];
  369.     
  370.     APTR NotePool;
  371.     
  372.     BOOL GUIRefresh;
  373.     
  374.     struct FileRequester *ImageFR;
  375.     struct FileRequester *MIDIFR;
  376.     struct ScreenModeRequester *ScreenModeRQ;
  377.     
  378.     ULONG TaskAlloc;
  379. };
  380.  
  381.  
  382. /* Some defines */
  383.  
  384. /* the opposite of noteon() */
  385. #define noteoff(m) ( voicemsg(m,MS_NoteOff) || (voicemsg(m,MS_NoteOn) && (!(m)->mm_Data2)) )
  386.  
  387. #define offsetof(s, m)  (size_t)(&(((s *)0)->m))
  388. #define MIN(a,b)    ((a) <= (b) ? (a) : (b))
  389. #define elementsof(a)  ((sizeof(a) / sizeof(a[0])))
  390.  
  391.  
  392. /* Intuition structures */
  393.  
  394. enum
  395. {
  396.     Menu_Ignore1,
  397.     Menu_Link,
  398.     Menu_Save,
  399.     Menu_Ignore2,
  400.     Menu_About,
  401.     Menu_Ignore3,
  402.     Menu_Quit,
  403.     Menu_Ignore4,
  404.     Menu_Kill,
  405.     Menu_Load,
  406.     Menu_Tile,
  407.     Menu_Ignore5,
  408.     Menu_Screenmode,
  409.     Menu_Fullscreen,
  410.     Menu_Ignore6,
  411.     Menu_Mode1,
  412.     Menu_Mode2,
  413.     Menu_Mode3,
  414.     Menu_Ignore7,
  415.     Menu_Double,
  416.     Menu_Ignore8,
  417.     Menu_Release,
  418.     Menu_Ignore9,
  419.     Menu_Play,
  420.     Menu_Stop,
  421.     Menu_Ignore10,
  422. };
  423.  
  424.  
  425. struct NewMenu FWNewMenu[]=
  426. {
  427.     /* nm_Type    nm_Label            nm_CommKey    nm_Flags            nm_MutualExclude    nm_UserData */
  428.     NM_TITLE,    "Project",            NULL,        0,                    0,                    (APTR)Menu_Ignore1,
  429.     NM_ITEM,    "MIDI Link...",        "L",        0,                    0,                    (APTR)Menu_Link,
  430.     NM_ITEM,    "Save Config",        "C",        0,                    0,                    (APTR)Menu_Save,
  431.     NM_ITEM,    NM_BARLABEL,        NULL,        0,                    0,                    (APTR)Menu_Ignore2,
  432.     NM_ITEM,    "About",            "?",        0,                    0,                    (APTR)Menu_About,
  433.     NM_ITEM,    NM_BARLABEL,        NULL,        0,                    0,                    (APTR)Menu_Ignore3,
  434.     NM_ITEM,    "Quit",                "Q",        0,                    0,                    (APTR)Menu_Quit,
  435.     NM_TITLE,    "Window",            NULL,        0,                    0,                    (APTR)Menu_Ignore4,
  436.     NM_ITEM,    "Remove Backdrop",    "R",        0,                    0,                    (APTR)Menu_Kill,
  437.     NM_ITEM,    "Load Backdrop...",    "B",        0,                    0,                    (APTR)Menu_Load,
  438.     NM_ITEM,    "Tile Backdrop",    "T",        CHECKIT|MENUTOGGLE,    0,                    (APTR)Menu_Tile,
  439.     NM_ITEM,    NM_BARLABEL,        NULL,        0,                    0,                    (APTR)Menu_Ignore5,
  440.     NM_ITEM,    "Set Screenmode...","M",        0,                    0,                    (APTR)Menu_Screenmode,
  441.     NM_ITEM,    "Full Screen",        "F",        CHECKIT|MENUTOGGLE,    0,                    (APTR)Menu_Fullscreen,
  442.     NM_TITLE,    "Rendering",        NULL,        0,                    0,                    (APTR)Menu_Ignore6,
  443.     NM_ITEM,    "Laser Mode",        "1",        CHECKIT,            (  2|4),            (APTR)Menu_Mode1,
  444.     NM_ITEM,    "Pixel Mode",        "2",        CHECKIT,            (1|  4),            (APTR)Menu_Mode2,
  445.     NM_ITEM,    "Fountain Mode",    "3",        CHECKIT,            (1|2  ),            (APTR)Menu_Mode3,
  446.     NM_ITEM,    NM_BARLABEL,        NULL,        0,                    0,                    (APTR)Menu_Ignore7,
  447.     NM_ITEM,    "Double Strength",    "D",        CHECKIT|MENUTOGGLE,    0,                    (APTR)Menu_Double,
  448.     NM_TITLE,    "MIDI",                NULL,        0,                    0,                    (APTR)Menu_Ignore8,
  449.     NM_ITEM,    "Release Notes",    "N",        0,                    0,                    (APTR)Menu_Release,
  450.     NM_ITEM,    NM_BARLABEL,        NULL,        0,                    0,                    (APTR)Menu_Ignore9,
  451.     NM_ITEM,    "Play MIDI file...","P",        0,                    0,                    (APTR)Menu_Play,
  452.     NM_ITEM,    "Stop playing",        "S",        0,                    0,                    (APTR)Menu_Stop,
  453.     NM_END,        NULL,                NULL,        0,                    0,                    (APTR)Menu_Ignore10,
  454. };
  455.  
  456.  
  457. /* Interrupt stuff */
  458.  
  459. struct Interrupt VertBlank =
  460. {
  461.     NULL,NULL,NT_INTERRUPT,-60,"Fireworks VBlank",    /* node, pri = -60 */
  462.     NULL,                                            /* data ptr, same as inputevent */
  463.     (void *)VBlankInterface                            /* code ptr */
  464. };
  465.  
  466. BOOL Watch = FALSE;
  467. ULONG IdleCount = 0;
  468.  
  469.  
  470. /*--------------*/
  471. /* Startup code */
  472. /*--------------*/
  473.  
  474. LONG __saveds mymain(void)
  475. {
  476.     LONG ReturnCode;
  477.     
  478.     struct    Process *MyProc;
  479.     
  480.     SysBase = *((struct ExecBase**)(0x4));
  481.     
  482.     MyProc = (struct Process*) FindTask(NULL);
  483.     
  484.     if (!MyProc->pr_CLI)
  485.     {
  486.         WBMode = TRUE;
  487.         ReturnCode = WBInterface(MyProc);
  488.     }
  489.     else
  490.     {
  491.         ReturnCode = ShellInterface();
  492.     }
  493.     
  494.     return(ReturnCode);
  495. }
  496.  
  497.  
  498.  
  499. /*---------------------*/
  500. /* Workbench Interface */
  501. /*---------------------*/
  502.  
  503. LONG WBInterface(struct Process *MyProc)
  504. {
  505.     struct WBStartup *wbmsg;
  506.     
  507.     LONG ReturnCode;
  508.     
  509.     WaitPort(&MyProc->pr_MsgPort);
  510.     
  511.     if (wbmsg = (struct WBStartup*)GetMsg(&MyProc->pr_MsgPort))
  512.     {
  513.         if (OpenLibs())
  514.         {
  515.             BPTR OldDir;
  516.             struct Prefs *pref;
  517.             
  518.             OldDir = CurrentDir(wbmsg->sm_ArgList->wa_Lock);
  519.             
  520.             if (!(pref = AllocVec(sizeof(struct Prefs),MEMF_ANY|MEMF_CLEAR)))
  521.             {
  522.                 Message("No memory for prefs!",NULL);
  523.             }
  524.             else
  525.             {
  526.                 InitPrefs(pref);
  527.                 
  528.                 ReturnCode = Fireworks(pref);
  529.                 
  530.                 FreeVec(pref);
  531.             }
  532.             
  533.             CurrentDir(OldDir);
  534.             
  535.             CloseLibs();
  536.         }
  537.         Forbid();
  538.         ReplyMsg((struct Message*)wbmsg);
  539.     }
  540.     return(ReturnCode);
  541. }
  542.  
  543.  
  544.  
  545. /*-----------------*/
  546. /* Shell Interface */
  547. /*-----------------*/
  548.  
  549. LONG  ShellInterface(void)
  550. {
  551.     LONG ReturnCode = RETURN_ERROR;
  552.     BPTR lock;
  553.     BPTR OldDir;
  554.     
  555.     if (OpenLibs())
  556.     {
  557.         if (!(lock = Lock("PROGDIR:", SHARED_LOCK)))
  558.         {
  559.             Message("Unable to locate program directory.",NULL);
  560.         }
  561.         else
  562.         {
  563.             /* CLI argument parsing */
  564.             
  565.             struct    ArgArray
  566.             {
  567.                 UBYTE *aa_Link;
  568.                 ULONG *aa_Mode;
  569.                 ULONG *aa_WinX;
  570.                 ULONG *aa_WinY;
  571.                 ULONG *aa_WinW;
  572.                 ULONG *aa_WinH;
  573.                 UBYTE *aa_Image;
  574.                 ULONG  aa_Tile;
  575.                 ULONG  aa_Double;
  576.                 ULONG  aa_Fullscreen;
  577.             } AA = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE};
  578.             
  579.             static UBYTE    *Template = "LINK/K,MODE/K/N,WINX/K/N,WINY/K/N,WINW/K/N,WINH/K/N,IMAGE/K,TILE/S,DOUBLE/S,FULLSCREEN/S";
  580.             struct RDArgs *RDArgs;
  581.             
  582.             struct Prefs *pref;
  583.             
  584.             ReturnCode = RETURN_FAIL;
  585.             
  586.             OldDir = CurrentDir(lock);
  587.             
  588.             if (!(pref = AllocVec(sizeof(struct Prefs),MEMF_ANY|MEMF_CLEAR)))
  589.             {
  590.                 Message("No memory for prefs!",NULL);
  591.             }
  592.             else
  593.             {
  594.                 InitPrefs(pref);
  595.                 
  596.                 if (RDArgs=ReadArgs(Template, (LONG *)&AA, 0))
  597.                 {
  598.                     if (AA.aa_Link) pref->Link = AA.aa_Link;
  599.                     if (AA.aa_Mode)
  600.                     {
  601.                         LONG mode = (*AA.aa_Mode) - 1;
  602.                         if (mode >=0 && mode < NUM_FWMODES) pref->FWMode = mode;
  603.                         else
  604.                             Message("Mode out of range! There are currently modes 1-%ld available.", NULL, NUM_FWMODES);
  605.                     }
  606.                     if (AA.aa_WinX) pref->WinX= *AA.aa_WinX;
  607.                     if (AA.aa_WinY) pref->WinY= *AA.aa_WinY;
  608.                     if (AA.aa_WinW) pref->WinW= *AA.aa_WinW;
  609.                     if (AA.aa_WinH) pref->WinH= *AA.aa_WinH;
  610.                     if (AA.aa_Image) pref->Image=AA.aa_Image;
  611.                     if (AA.aa_Tile) pref->Flags |= PREFF_TILE;
  612.                     if (AA.aa_Double) pref->Flags |= PREFF_DOUBLE;
  613.                     if (AA.aa_Fullscreen) pref->Flags |= PREFF_FULLSCREEN;
  614.                     
  615.                     ReturnCode = Fireworks(pref);
  616.                     
  617.                     FreeArgs(RDArgs);
  618.                 }
  619.                 else
  620.                 {
  621.                     PrintFault(IoErr(),"vu");
  622.                 }
  623.                 
  624.                 FreeVec(pref);
  625.             }
  626.             
  627.             CurrentDir(OldDir);
  628.             
  629.             UnLock(lock);
  630.         }
  631.         CloseLibs();
  632.     }
  633.     return(ReturnCode);
  634. }
  635.  
  636.  
  637.  
  638. /*-----------------------------*/
  639. /* GUI and MIDI initialisation */
  640. /*-----------------------------*/
  641.  
  642. LONG Fireworks(struct Prefs *pref)
  643. {
  644.     LONG ReturnCode = RETURN_FAIL;
  645.     
  646.     struct Globals *glob;
  647.     
  648.     BYTE OldPri;
  649.     
  650.     MyTask = FindTask(NULL);
  651.     
  652.     if (!(glob = AllocVec(sizeof(struct Globals), MEMF_ANY|MEMF_CLEAR)))
  653.     {
  654.         Message("No memory for globals!",NULL);
  655.     }
  656.     else
  657.     {
  658.         InitGlobals(glob);
  659.         
  660.         if (OpenGUI(glob,pref))
  661.         {
  662.             if (!((glob->NotePool = CreatePool(MEMF_ANY,8192,4096))))
  663.             {
  664.                 Message("No memory for NotePool!",NULL);
  665.             }
  666.             else
  667.             {
  668.                 if (!(glob->midi = CreateMidi(
  669.                     MIDI_Name, "VU Meters",
  670.                     MIDI_RecvSignal, SIGBREAKB_CTRL_E,
  671.                     MIDI_MsgQueue,   2000,
  672.                     MIDI_ErrFilter, CMEF_All,
  673.                     TAG_DONE)))
  674.                 {
  675.                     Message("Cannot create MIDI port!",NULL);
  676.                 }
  677.                 else
  678.                 {
  679.                     if (!(glob->link = AddMidiLink(glob->midi, MLTYPE_Receiver,
  680.                         MLINK_Name, "VU Meter Link",
  681.                         MLINK_Location, pref->Link,
  682.                         MLINK_EventMask, CMF_Note|CMF_Mode,
  683.                         MLINK_Comment,  "Fireworks [Input]",
  684.                         TAG_DONE)))
  685.                     {
  686.                         Message("Cannot create link to MIDI interface '%s'",NULL,pref->Link);
  687.                     }
  688.                     else
  689.                     {
  690.                         TitleWindow(glob, "Fireworks [%s] [idle]", pref->Link);
  691.                         
  692.                         if (!(glob->treq = OpenTimer()))
  693.                         {
  694.                             
  695.                         }
  696.                         else
  697.                         {
  698.                             OldPri = MyTask->tc_Node.ln_Pri;
  699.                             
  700.                             MainLoop(glob, pref);
  701.                             
  702.                             WaitAsync(glob);
  703.                             
  704.                             ReturnCode = RETURN_OK;
  705.                             
  706.                             SetTaskPri(MyTask, OldPri);
  707.                             
  708.                             CloseTimer(glob->treq);
  709.                             glob->treq=NULL;
  710.                         }
  711.                         RemoveMidiLink(glob->link);
  712.                         glob->link = NULL;
  713.                     }
  714.                     DeleteMidi(glob->midi);
  715.                     glob->midi = NULL;
  716.                 }
  717.                 DeletePool(glob->NotePool);
  718.                 glob->NotePool = NULL;
  719.             }
  720.             CloseGUI(glob, pref);
  721.         }
  722.         
  723.         if (glob->ImageFR)
  724.         {
  725.             FreeAslRequest(glob->ImageFR);
  726.             glob->ImageFR = NULL;
  727.         }
  728.         
  729.         if (glob->MIDIFR)
  730.         {
  731.             FreeAslRequest(glob->MIDIFR);
  732.             glob->MIDIFR = NULL;
  733.         }
  734.         
  735.         if (glob->ScreenModeRQ)
  736.         {
  737.             FreeAslRequest(glob->ScreenModeRQ);
  738.             glob->ScreenModeRQ = NULL;
  739.         }
  740.         
  741.         FreeVec(glob);
  742.     }
  743.     return(ReturnCode);
  744. }
  745.  
  746.  
  747. /*--------------------*/
  748. /* Set Prefs defaults */
  749. /*--------------------*/
  750.  
  751. void InitPrefs(struct Prefs *pref)
  752. {
  753.     pref->Link = "out.0";
  754.     pref->WinX = 100;
  755.     pref->WinY = 200;
  756.     pref->WinW = 256;
  757.     pref->WinH = 256;
  758.     pref->Flags = PREFF_BACKDROP;
  759.     pref->Image = "PROGDIR:Backdrop.Pic";
  760.     pref->ScreenMode = -1L;
  761.     pref->ScreenWidth = 0;
  762.     pref->ScreenHeight = 0;
  763.     pref->ScreenDepth = 0;
  764.     pref->OverscanType = 0;
  765.     pref->AutoScroll = FALSE;
  766.     pref->FWMode = ParabolicMode2;
  767. }
  768.  
  769.  
  770. /*--------------------*/
  771. /* Initialize globals */
  772. /*--------------------*/
  773.  
  774. void InitGlobals(struct Globals *glob)
  775. {
  776.     UWORD i;
  777.     
  778.     for (i=0; i<NUMPENS; i++) glob->PenArray[i] = -1L;
  779. }
  780.  
  781.  
  782. /*-------------------------------*/
  783. /* Open the GUI (Screen, Window) */
  784. /*-------------------------------*/
  785.  
  786. BOOL OpenGUI(struct Globals *glob, struct Prefs *pref)
  787. {
  788.     BOOL Success = FALSE;
  789.     
  790.     struct Screen *wbscr;
  791.     
  792.     WORD minw, minh;
  793.     WORD maxw, maxh;
  794.     
  795.     UWORD mode;
  796.     
  797.     glob->Screen = NULL;
  798.     
  799.     if (pref->Flags & PREFF_FULLSCREEN)
  800.     {
  801.         if (pref->ScreenMode == -1L)
  802.         {
  803.             if (!SelectScreenMode(glob, pref, &glob->ScreenModeRQ))
  804.             {
  805.                 pref->Flags &= ~(PREFF_FULLSCREEN);
  806.             }
  807.         }
  808.     }
  809.     
  810.     if (pref->Flags & PREFF_FULLSCREEN)
  811.     {
  812.         if (pref->ScreenMode != -1L)
  813.         {
  814.             struct Screen *scr = NULL;
  815.             
  816.             /* maybe screen couldn't be closed before (visitor window) */
  817.             if (glob->OpenedScreen) CloseScreen(glob->OpenedScreen);
  818.             
  819.             if (!(scr = OpenScreenTags(NULL,
  820.                 SA_DisplayID, pref->ScreenMode,
  821.                 SA_Width, (ULONG)pref->ScreenWidth,
  822.                 SA_Height, (ULONG)pref->ScreenHeight,
  823.                 SA_Depth, (ULONG)pref->ScreenDepth,
  824.                 SA_Overscan, (ULONG)pref->OverscanType,
  825.                 SA_AutoScroll, (ULONG)pref->AutoScroll,
  826.                 SA_SharePens, (ULONG)TRUE,
  827.                 SA_Interleaved, (ULONG)TRUE,
  828.                 SA_PubName, "Fireworks",
  829.                 SA_Colors32, ScreenPalette,
  830.                 SA_Pens, PenArray,
  831.                 TAG_DONE )))
  832.             {
  833.                 Message("Unable to open selected screen!",NULL);
  834.             }
  835.             else
  836.             {
  837.                 glob->Screen = glob->OpenedScreen = scr;
  838.                 
  839.                 if (glob->LockedScreen)
  840.                 {
  841.                     UnlockPubScreen(NULL, glob->LockedScreen);
  842.                     glob->LockedScreen = NULL;
  843.                 }
  844.             }
  845.         }
  846.     }
  847.     else
  848.     {
  849.         if (!glob->LockedScreen)
  850.         {
  851.             glob->LockedScreen = GetScreen(glob);
  852.         }
  853.         glob->Screen = glob->LockedScreen;
  854.     }
  855.     
  856.     if (glob->Screen)
  857.     {
  858.         if (!(glob->VisualInfo = GetVisualInfo(glob->Screen, TAG_DONE)))
  859.         {
  860.             Message("No visual info!",NULL);
  861.         }
  862.         else
  863.         {
  864.             glob->ww = pref->WinW;
  865.             glob->wh = pref->WinH;
  866.             
  867.             if (!(WindowLayout(glob, &minw, &minh, &maxw, &maxh )))
  868.             {
  869.                 Message("Couldn't layout window!",NULL);
  870.             }
  871.             else
  872.             {
  873.                 if (pref->Flags & PREFF_FULLSCREEN)
  874.                 {
  875.                     glob->Window = OpenWindowTags( NULL,
  876.                             WA_PubScreen, glob->Screen,
  877.                             WA_Left, 0,
  878.                             WA_Top, glob->Screen->BarHeight+1,
  879.                             WA_Width, pref->ScreenWidth,
  880.                             WA_Height, pref->ScreenHeight-(glob->Screen->BarHeight+1),
  881.                             WA_Backdrop, TRUE,
  882.                             WA_Borderless, TRUE,
  883.                             WA_Activate, TRUE,
  884.                             WA_IDCMP, IDCMP_MENUPICK|IDCMP_REFRESHWINDOW,
  885.                             WA_SimpleRefresh, TRUE,
  886.                             WA_NewLookMenus, TRUE,
  887.                             TAG_DONE );
  888.                 }
  889.                 else
  890.                 {
  891.                     glob->Window = OpenWindowTags( NULL,
  892.                             WA_PubScreen, glob->Screen,
  893.                             WA_Title, "Fireworks",
  894.                             WA_Left, pref->WinX,
  895.                             WA_Top, pref->WinY,
  896.                             WA_InnerWidth, (ULONG)glob->ww,
  897.                             WA_InnerHeight, (ULONG)glob->wh,
  898.                             WA_GimmeZeroZero, TRUE,
  899.                             WA_DepthGadget, TRUE,
  900.                             WA_SizeGadget, TRUE,
  901.                             WA_SizeBBottom, TRUE,
  902.                             WA_CloseGadget, TRUE,
  903.                             WA_DragBar, TRUE,
  904.                             WA_Activate, TRUE,
  905.                             WA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_NEWSIZE|IDCMP_MENUPICK|IDCMP_REFRESHWINDOW,
  906.                             WA_SimpleRefresh, TRUE,
  907.                             WA_NewLookMenus, TRUE,
  908.                             TAG_DONE );
  909.                 }
  910.                 
  911.                 if (!glob->Window)
  912.                 {
  913.                     Message("Couldn't open window!",NULL);
  914.                 }
  915.                 else
  916.                 {
  917.                     glob->ProcWindow = ((struct Process*)MyTask)->pr_WindowPtr;
  918.                     ((struct Process*)MyTask)->pr_WindowPtr = glob->Window;
  919.                     
  920.                     if ( wbscr = LockPubScreen("Workbench") )
  921.                     {
  922.                         if (glob->Screen == wbscr)
  923.                         {
  924.                             glob->AppWindow = AddAppWindow( 1, NULL, glob->Window, &((struct Process*)MyTask)->pr_MsgPort, TAG_DONE);
  925.                         }
  926.                         
  927.                         UnlockPubScreen( NULL, wbscr );
  928.                     }
  929.                     
  930.                     glob->ww = glob->Window->Width  - glob->Window->BorderLeft-glob->Window->BorderRight ;
  931.                     glob->wh = glob->Window->Height - glob->Window->BorderTop -glob->Window->BorderBottom;
  932.                     
  933.                     glob->Window->MinWidth  = minw + glob->Window->BorderLeft+glob->Window->BorderRight;
  934.                     glob->Window->MinHeight = minh + glob->Window->BorderTop +glob->Window->BorderBottom;
  935.                     glob->Window->MaxWidth  = maxw + glob->Window->BorderLeft+glob->Window->BorderRight;
  936.                     glob->Window->MaxHeight = maxh + glob->Window->BorderTop +glob->Window->BorderBottom;
  937.                     
  938.                     if (!(InitOrUpdateGraphics(glob,pref)))
  939.                     {
  940.                         Message("Failed to initialize graphics!",NULL);
  941.                     }
  942.                     else
  943.                     {
  944.                         BltBitMapRastPort(glob->PaintBitMap, 0, 0, glob->Window->RPort, 0, 0, glob->ww, glob->wh, 0xc0);
  945.                         
  946.                         if (pref->Flags & PREFF_BACKDROP)
  947.                             if (pref->Image) LoadImage(glob,pref);
  948.                         
  949.                         if (pref->Flags & PREFF_DOUBLE)
  950.                             FWNewMenu[Menu_Double].nm_Flags |= CHECKED;
  951.                         else
  952.                             FWNewMenu[Menu_Double].nm_Flags &= (~CHECKED);
  953.                         
  954.                         if (pref->Flags & PREFF_TILE)
  955.                             FWNewMenu[Menu_Tile].nm_Flags |= CHECKED;
  956.                         else
  957.                             FWNewMenu[Menu_Tile].nm_Flags &= (~CHECKED);
  958.                         
  959.                         if (pref->Flags & PREFF_FULLSCREEN)
  960.                             FWNewMenu[Menu_Fullscreen].nm_Flags |= CHECKED;
  961.                         else
  962.                             FWNewMenu[Menu_Fullscreen].nm_Flags &= (~CHECKED);
  963.                         
  964.                         for (mode = 0; mode < NUM_FWMODES ; mode++)
  965.                         {
  966.                             if (pref->FWMode == mode)
  967.                                 FWNewMenu[Menu_Mode1+mode].nm_Flags |= CHECKED;
  968.                             else
  969.                                 FWNewMenu[Menu_Mode1+mode].nm_Flags &= (~CHECKED);
  970.                         }
  971.                         
  972.                         if (!(glob->Menu=(struct Menu *)CreateMenus(FWNewMenu, TAG_DONE)))
  973.                         {
  974.                             Message("Failed to create intuition menu.",NULL);
  975.                         }
  976.                         else
  977.                         {
  978.                             LayoutMenus(glob->Menu, glob->VisualInfo, GTMN_NewLookMenus, TRUE, TAG_DONE);
  979.                             SetMenuStrip(glob->Window, glob->Menu);
  980.                             
  981.                             Success = TRUE;
  982.                         }
  983.                     }
  984.                 }
  985.             }
  986.         }
  987.     }
  988.     
  989.     if (!Success) CloseGUI(glob, pref);
  990.     
  991.     return(Success);
  992. }
  993.  
  994.  
  995. /*----------------------*/
  996. /* Set the window title */
  997. /*----------------------*/
  998.  
  999. void TitleWindow(struct Globals *glob, UBYTE *Text, ...)
  1000. {
  1001.     va_list Arg;
  1002.     va_start(Arg,Text);
  1003.     
  1004.     VSPrintf(glob->WTitle, Text, Arg);
  1005.     
  1006.     if (glob->OpenedScreen)
  1007.     {
  1008.         SetWindowTitles(glob->Window, (UBYTE*) ~0, glob->WTitle);
  1009.     }
  1010.     else
  1011.     {
  1012.         SetWindowTitles(glob->Window, glob->WTitle, (UBYTE*) ~0);
  1013.     }
  1014.     
  1015.     va_end(Arg);
  1016. }
  1017.  
  1018.  
  1019. /*---------------------------*/
  1020. /* Choose desired screenmode */
  1021. /*---------------------------*/
  1022.  
  1023. BOOL SelectScreenMode(struct Globals *glob, struct Prefs *pref, struct ScreenModeRequester **srq)
  1024. {
  1025.     BOOL Result = FALSE;
  1026.     
  1027.     ULONG InitialDisplayID = pref->ScreenMode;
  1028.     UWORD InitialDisplayDepth = pref->ScreenDepth;
  1029.     UWORD InitialDisplayWidth = pref->ScreenWidth;
  1030.     UWORD InitialDisplayHeight = pref->ScreenHeight;
  1031.     ULONG InitialOverscanType = pref->OverscanType;
  1032.     BOOL InitialAutoScroll = pref->AutoScroll;
  1033.     
  1034.     if (InitialDisplayID == -1L)
  1035.     {
  1036.         struct DimensionInfo dims;
  1037.         
  1038.         if ((InitialDisplayID = BestModeID(
  1039.             BIDTAG_NominalWidth, 320,
  1040.             BIDTAG_NominalHeight, 240,
  1041.             BIDTAG_Depth, 8,
  1042.             TAG_DONE )) == INVALID_ID)
  1043.         {
  1044.             InitialDisplayID = LORES_KEY;
  1045.         }
  1046.         
  1047.         InitialOverscanType = OSCAN_TEXT;
  1048.         InitialAutoScroll = TRUE;
  1049.         
  1050.         if (GetDisplayInfoData(NULL, (UBYTE*)&dims, sizeof(dims), DTAG_DIMS, InitialDisplayID) < sizeof(dims))
  1051.         {
  1052.             InitialDisplayDepth = 8;
  1053.             InitialDisplayWidth = 320;
  1054.             InitialDisplayHeight = 240;
  1055.         }
  1056.         else
  1057.         {
  1058.             InitialDisplayDepth  = dims.MaxDepth;
  1059.             InitialDisplayWidth  = (dims.TxtOScan.MaxX-dims.TxtOScan.MinX) + 1;
  1060.             InitialDisplayHeight = (dims.TxtOScan.MaxY-dims.TxtOScan.MinY) + 1;
  1061.         }
  1062.     }
  1063.     
  1064.     if (!(*srq))
  1065.     {
  1066.         if (!((*srq) = AllocAslRequestTags(ASL_ScreenModeRequest,
  1067.             ASLSM_TitleText, "Select screen mode",
  1068.             TAG_DONE)))
  1069.         {
  1070.             Message("Unable to allocate ASL screenmode requester.",NULL);
  1071.         }
  1072.     }
  1073.     
  1074.     if (*srq)
  1075.     {
  1076.         Result = AslRequestTags(*srq,
  1077.             ASLSM_Screen, GetScreen(glob),
  1078.             ASLSM_DoWidth, TRUE,
  1079.             ASLSM_DoHeight, TRUE,
  1080.             ASLSM_DoDepth, TRUE,
  1081.             ASLSM_DoOverscanType, TRUE,
  1082.             ASLSM_DoAutoScroll, TRUE,
  1083.             ASLSM_InitialDisplayID, InitialDisplayID,
  1084.             ASLSM_InitialDisplayWidth, InitialDisplayWidth,
  1085.             ASLSM_InitialDisplayHeight, InitialDisplayHeight,
  1086.             ASLSM_InitialDisplayDepth, InitialDisplayDepth,
  1087.             ASLSM_InitialOverscanType, InitialOverscanType,
  1088.             ASLSM_InitialAutoScroll, InitialAutoScroll,
  1089.             TAG_DONE);
  1090.         
  1091.         if (Result)
  1092.         {
  1093.             pref->ScreenMode=(*srq)->sm_DisplayID;
  1094.             pref->ScreenWidth=(*srq)->sm_DisplayWidth;
  1095.             pref->ScreenHeight=(*srq)->sm_DisplayHeight;
  1096.             pref->ScreenDepth=(*srq)->sm_DisplayDepth;
  1097.             pref->OverscanType=(*srq)->sm_OverscanType;
  1098.             pref->AutoScroll=(*srq)->sm_AutoScroll;
  1099.         }
  1100.     }
  1101.     return(Result);
  1102. }
  1103.  
  1104.  
  1105. /*--------------------------------*/
  1106. /* Close the GUI (Screen, Window) */
  1107. /*--------------------------------*/
  1108.  
  1109. void CloseGUI(struct Globals *glob, struct Prefs *pref)
  1110. {
  1111.     if (glob->Window)
  1112.     {
  1113.         if (glob->Menu)
  1114.         {
  1115.             ClearMenuStrip(glob->Window);
  1116.             
  1117.             FreeMenus(glob->Menu);
  1118.             glob->Menu = NULL;
  1119.         }
  1120.         
  1121.         FreeGraphics(glob);
  1122.         
  1123.         ((struct Process*)MyTask)->pr_WindowPtr=glob->ProcWindow;
  1124.         glob->ProcWindow = NULL;
  1125.         
  1126.         if (glob->LockedScreen)
  1127.         {
  1128.             pref->WinX = glob->Window->LeftEdge;
  1129.             pref->WinY = glob->Window->TopEdge;
  1130.             pref->WinW = glob->ww;
  1131.             pref->WinH = glob->wh;
  1132.         }
  1133.         
  1134.         if (glob->AppWindow)
  1135.         {
  1136.             RemoveAppWindow(glob->AppWindow);
  1137.             glob->AppWindow = NULL;
  1138.         }
  1139.         
  1140.         CloseWindow(glob->Window);
  1141.         glob->Window = NULL;
  1142.     }
  1143.     
  1144.     if (glob->Screen)
  1145.     {
  1146.         if (glob->VisualInfo)
  1147.         {
  1148.             FreeVisualInfo(glob->VisualInfo);
  1149.             glob->VisualInfo = NULL;
  1150.         }
  1151.         
  1152.         if (glob->LockedScreen)
  1153.         {
  1154.             UnlockPubScreen(NULL, glob->LockedScreen);
  1155.             glob->LockedScreen = NULL;
  1156.         }
  1157.         
  1158.         if (glob->OpenedScreen)
  1159.         {
  1160.             if (CloseScreen(glob->OpenedScreen))
  1161.                 glob->OpenedScreen = NULL;
  1162.         }
  1163.         
  1164.         glob->Screen = NULL;
  1165.     }
  1166. }
  1167.  
  1168.  
  1169. /*-----------------------------*/
  1170. /* Calculate window dimensions */
  1171. /*-----------------------------*/
  1172.  
  1173. BOOL WindowLayout(struct Globals *glob, WORD *minw, WORD *minh, WORD *maxw, WORD *maxh)
  1174. {
  1175.     BOOL Success = FALSE;
  1176.     
  1177.     *minw=64;
  1178.     *minh=64;
  1179.     
  1180.     *maxw=1024;
  1181.     *maxh=1024;
  1182.     
  1183.     if (glob->ww < *minw) glob->ww = *minw;
  1184.     if (glob->wh < *minh) glob->wh = *minh;
  1185.     
  1186.     if (glob->ww > *maxw) glob->ww = *maxw;
  1187.     if (glob->wh > *maxh) glob->wh = *maxh;
  1188.     
  1189.     Success=TRUE;
  1190.     
  1191.     return(Success);
  1192. }
  1193.  
  1194.  
  1195.  
  1196. /*-----------------*/
  1197. /* Main event loop */
  1198. /*-----------------*/
  1199.  
  1200. UWORD NoteArray[128];
  1201. UBYTE ChanUse[16];
  1202.  
  1203. void MainLoop(struct Globals *glob, struct Prefs *pref)
  1204. {
  1205.     UWORD Mask = 0xffff;
  1206.     
  1207.     BOOL Active;
  1208.     APTR fwdata;
  1209.     
  1210.     ULONG signals;
  1211.     ULONG gotsignals;
  1212.     struct IntuiMessage *imsg;
  1213.     ULONG Cl;
  1214.     UWORD Co;
  1215.     APTR IA;
  1216.     
  1217.     ULONG timersig = (1L << glob->treq->tr_node.io_Message.mn_ReplyPort->mp_SigBit);
  1218.     ULONG procsig  = (1L << ((struct Process*)MyTask)->pr_MsgPort.mp_SigBit);
  1219.     ULONG winsig   = (1L << glob->Window->UserPort->mp_SigBit);
  1220.     BOOL TimerActive = FALSE;
  1221.     
  1222.     UBYTE Err;
  1223.     
  1224.     Active=TRUE;
  1225.     glob->GUIRefresh=FALSE;
  1226.     
  1227.     memset(NoteArray,0,sizeof(NoteArray));
  1228.     memset(ChanUse  ,0,sizeof(ChanUse  ));
  1229.     
  1230.     Watch = FALSE;
  1231.     AddIntServer(INTB_VERTB, &VertBlank);
  1232.     
  1233.     glob->ww = glob->Window->Width  - glob->Window->BorderLeft-glob->Window->BorderRight ;
  1234.     glob->wh = glob->Window->Height - glob->Window->BorderTop -glob->Window->BorderBottom;
  1235.     
  1236.     if (!(fwdata = (FWDefinitions[pref->FWMode].InitFireworks)(glob, pref)))
  1237.     {
  1238.         Message("Unable to initialize fireworks.", "Oh no");
  1239.     }
  1240.     else
  1241.     {
  1242.         signals = winsig | procsig | timersig | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_E;
  1243.         
  1244.         TimerActive = FALSE;
  1245.         SetTaskPri(MyTask, HIGHPRI);
  1246.         
  1247.         while(Active)
  1248.         {
  1249.             if (glob->GUIRefresh)
  1250.             {
  1251.                 BOOL SaveWatch = Watch;
  1252.                 Watch = FALSE;
  1253.                 
  1254.                 CloseGUI(glob, pref);
  1255.                 
  1256.                 if (!OpenGUI(glob, pref))
  1257.                 {
  1258.                     pref->Flags &= (~PREFF_FULLSCREEN);
  1259.                     
  1260.                     if (!OpenGUI(glob, pref))
  1261.                     {
  1262.                         Active = FALSE;
  1263.                         break;
  1264.                     }
  1265.                 }
  1266.                 
  1267.                 TitleWindow(glob, "Fireworks [%s]%s", pref->Link, TimerActive ? "" : " [idle]");
  1268.                 
  1269.                 winsig = (1L << glob->Window->UserPort->mp_SigBit);
  1270.                 signals = winsig | procsig | timersig | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_E;
  1271.                 
  1272.                 if (fwdata) (FWDefinitions[pref->FWMode].RethinkWindow)(fwdata);
  1273.                 
  1274.                 glob->GUIRefresh = FALSE;
  1275.                 
  1276.                 Watch=SaveWatch;
  1277.             }
  1278.             
  1279.             gotsignals = Wait(signals);
  1280.             
  1281.             if (gotsignals & winsig)
  1282.             {
  1283.                 while(Active && (imsg=(struct IntuiMessage*)GetMsg(glob->Window->UserPort)))
  1284.                 {
  1285.                     Cl=imsg->Class;
  1286.                     Co=imsg->Code;
  1287.                     IA=imsg->IAddress;
  1288.                     ReplyMsg((struct Message*)imsg);
  1289.                     
  1290.                     if (Cl==IDCMP_CLOSEWINDOW)
  1291.                     {
  1292.                         if (AskAsync(glob))
  1293.                         {
  1294.                             Active=FALSE;
  1295.                             break;
  1296.                         }
  1297.                         else
  1298.                             AsyncMessage(glob,CloseTask, "Cannot quit yet. Please close all open requesters.","I will");
  1299.                     }
  1300.                     
  1301.                     if (Cl==IDCMP_NEWSIZE)
  1302.                     {
  1303.                         BOOL SaveWatch = Watch;
  1304.                         Watch = FALSE;
  1305.                         
  1306.                         glob->ww = pref->WinW = glob->Window->Width  - glob->Window->BorderLeft-glob->Window->BorderRight ;
  1307.                         glob->wh = pref->WinH = glob->Window->Height - glob->Window->BorderTop -glob->Window->BorderBottom;
  1308.                         
  1309.                         if (!(InitOrUpdateGraphics(glob, pref)))
  1310.                         {
  1311.                             Message("Failed to update graphics!",NULL);
  1312.                         }
  1313.                         
  1314.                         if (glob->PaintBitMap)
  1315.                         {
  1316.                             BltBitMapRastPort(glob->PaintBitMap, 0, 0, glob->Window->RPort, 0, 0, glob->ww, glob->wh, 0xc0);
  1317.                         }
  1318.                         else EraseRect(glob->Window->RPort, 0, 0, (glob->ww)-1, (glob->wh)-1);
  1319.                         
  1320.                         if (fwdata) (FWDefinitions[pref->FWMode].RethinkWindow)(fwdata);
  1321.                         
  1322.                         Watch = SaveWatch;
  1323.                     }
  1324.                     
  1325.                     if (Cl==IDCMP_REFRESHWINDOW)
  1326.                     {
  1327.                         BeginRefresh( glob->Window );
  1328.                         
  1329.                         if (glob->PaintBitMap)
  1330.                         {
  1331.                             BltBitMapRastPort(glob->PaintBitMap, 0, 0, glob->Window->RPort, 0, 0, glob->ww, glob->wh, 0xc0);
  1332.                         }
  1333.                         else EraseRect(glob->Window->RPort, 0, 0, (glob->ww)-1, (glob->wh)-1);
  1334.                         
  1335.                         EndRefresh( glob->Window, TRUE );
  1336.                     }
  1337.                     
  1338.                     if (Cl==IDCMP_MENUPICK)
  1339.                     {
  1340.                         BOOL SaveWatch = Watch;
  1341.                         
  1342.                         struct MenuItem *n;
  1343.                         ULONG pick;
  1344.                         
  1345.                         Watch = FALSE;
  1346.                         
  1347.                         while( (Co != MENUNULL) && Active)
  1348.                         {
  1349.                             n = ItemAddress( glob->Window->MenuStrip, (ULONG)Co );
  1350.                             pick = (ULONG) GTMENUITEM_USERDATA( n );
  1351.                             
  1352.                             switch(pick)
  1353.                             {
  1354.                                 case Menu_Link:
  1355.                                 {
  1356.                                     APTR listreq;
  1357.                                     
  1358.                                     if (!(listreq = AllocListRequest(
  1359.                                         LISTREQ_Screen, GetScreen(glob),
  1360.                                         LISTREQ_TitleText, "Select input link",
  1361.                                         TAG_DONE )))
  1362.                                     {
  1363.                                         Message("Couldn't allocate a list requester.",NULL);
  1364.                                     }
  1365.                                     else
  1366.                                     {
  1367.                                         if (pref->Link != pref->NewLink)
  1368.                                         {
  1369.                                             strncpy(pref->NewLink, (glob->link)->ml_Location->mcl_Node.ln_Name, sizeof(pref->NewLink));
  1370.                                             pref->NewLink[sizeof(pref->NewLink)-1] = 0;
  1371.                                         }
  1372.                                         
  1373.                                         if (SelectCluster( listreq, pref->NewLink, sizeof(pref->NewLink), TAG_DONE ))
  1374.                                         {
  1375.                                             if (strcmp((glob->link)->ml_Location->mcl_Node.ln_Name,pref->NewLink))
  1376.                                             {
  1377.                                                 struct MidiLink *newlink;
  1378.                                                 
  1379.                                                 if (!(newlink = AddMidiLink(glob->midi, MLTYPE_Receiver,
  1380.                                                     MLINK_Name, "VU Meter Link",
  1381.                                                     MLINK_Location, pref->NewLink,
  1382.                                                     MLINK_EventMask, CMF_Note|CMF_Mode,
  1383.                                                     MLINK_Comment,  "Fireworks [Input]",
  1384.                                                     TAG_DONE)))
  1385.                                                 {
  1386.                                                     Message("Cannot create link to MIDI interface '%s'",NULL,pref->NewLink);
  1387.                                                 }
  1388.                                                 else
  1389.                                                 {
  1390.                                                     RemoveMidiLink( glob->link );
  1391.                                                     FlushMidi ( glob->midi );
  1392.                                                     
  1393.                                                     glob->link = newlink;
  1394.                                                     pref->Link = pref->NewLink;
  1395.                                                     
  1396.                                                     TitleWindow(glob, "Fireworks [%s]%s", pref->Link, TimerActive ? "" : " [idle]");
  1397.                                                     
  1398.                                                     memset(NoteArray,0,sizeof(NoteArray));
  1399.                                                     memset(ChanUse  ,0,sizeof(ChanUse  ));
  1400.                                                     
  1401.                                                     if (fwdata) (FWDefinitions[pref->FWMode].FreeNoteData)(fwdata);
  1402.                                                 }
  1403.                                             }
  1404.                                         }
  1405.                                         FreeListRequest(listreq);
  1406.                                     }
  1407.                                 }
  1408.                                 break;
  1409.                                 
  1410.                                 case Menu_Save:
  1411.                                 {
  1412.                                     AsyncMessage(glob,SaveTask, "Save Config\nIsn't implemented... eeeh!","Damn");
  1413.                                 }
  1414.                                 break;
  1415.                                 
  1416.                                 case Menu_About:
  1417.                                 {
  1418.                                     AsyncMessage(glob,AboutTask, "Fireworks\n© 1998 by Christian Buchner\nflowerp@eikon.e-technik.tu-muenchen.de","Cool");
  1419.                                 }
  1420.                                 break;
  1421.                                 
  1422.                                 case Menu_Quit:
  1423.                                 {
  1424.                                     if (AskAsync(glob))
  1425.                                         Active = FALSE;
  1426.                                     else
  1427.                                         AsyncMessage(glob,CloseTask, "Cannot quit yet. Please close all open requesters.","I will");
  1428.                                 }
  1429.                                 break;
  1430.                                 
  1431.                                 case Menu_Kill:
  1432.                                 {
  1433.                                     pref->Flags &= (~PREFF_BACKDROP);
  1434.                                     
  1435.                                     if (glob->dto)
  1436.                                     {
  1437.                                         SetAPen(glob->Window->RPort, glob->PenArray[Backgroundpen]);
  1438.                                         RectFill(glob->Window->RPort, 0, 0, (glob->ww)-1, (glob->wh)-1);
  1439.                                         
  1440.                                         DisposeDTObject(glob->dto);
  1441.                                         glob->dto = NULL;
  1442.                                         
  1443.                                         if (!(InitOrUpdateGraphics(glob,pref)))
  1444.                                         {
  1445.                                             Message("Failed to update graphics!",NULL);
  1446.                                         }
  1447.                                         
  1448.                                         if (glob->PaintBitMap)
  1449.                                         {
  1450.                                             BltBitMapRastPort(glob->PaintBitMap, 0, 0, glob->Window->RPort, 0, 0, glob->ww, glob->wh, 0xc0);
  1451.                                         }
  1452.                                         else EraseRect(glob->Window->RPort, 0, 0, (glob->ww)-1, (glob->wh)-1);
  1453.                                     }
  1454.                                 }
  1455.                                 break;
  1456.                                 
  1457.                                 case Menu_Load:
  1458.                                 {
  1459.                                     if (pref->Image != pref->NewImage)
  1460.                                     {
  1461.                                         strncpy(pref->NewImage, pref->Image, sizeof(pref->NewImage));
  1462.                                         pref->NewImage[sizeof(pref->NewImage)-1] = 0;
  1463.                                     }
  1464.                                     
  1465.                                     AsyncSelectImage(glob, pref);
  1466.                                 }
  1467.                                 break;
  1468.                                 
  1469.                                 case Menu_Tile:
  1470.                                 {
  1471.                                     if (n->Flags & CHECKED)
  1472.                                         pref->Flags |= PREFF_TILE;
  1473.                                     else
  1474.                                         pref->Flags &= (~PREFF_TILE);
  1475.                                     
  1476.                                     if (!(InitOrUpdateGraphics(glob,pref)))
  1477.                                     {
  1478.                                         Message("Failed to update graphics!",NULL);
  1479.                                     }
  1480.                                     
  1481.                                     if (glob->PaintBitMap)
  1482.                                     {
  1483.                                         BltBitMapRastPort(glob->PaintBitMap, 0, 0, glob->Window->RPort, 0, 0, glob->ww, glob->wh, 0xc0);
  1484.                                     }
  1485.                                     else EraseRect(glob->Window->RPort, 0, 0, (glob->ww)-1, (glob->wh)-1);
  1486.                                 }
  1487.                                 break;
  1488.                                 
  1489.                                 case Menu_Fullscreen:
  1490.                                 {
  1491.                                     if (n->Flags & CHECKED)
  1492.                                     {
  1493.                                         if (pref->ScreenMode == -1L)
  1494.                                         {
  1495.                                             n->Flags &= (~CHECKED);
  1496.                                             AsyncSelectScreenMode(glob, pref);
  1497.                                         }
  1498.                                         else
  1499.                                         {
  1500.                                             pref->Flags |= PREFF_FULLSCREEN;
  1501.                                             glob->GUIRefresh = TRUE;
  1502.                                         }
  1503.                                     }
  1504.                                     else
  1505.                                     {
  1506.                                         glob->GUIRefresh = TRUE;
  1507.                                         pref->Flags &= (~PREFF_FULLSCREEN);
  1508.                                     }
  1509.                                 }
  1510.                                 break;
  1511.                                 
  1512.                                 case Menu_Screenmode:
  1513.                                 {
  1514.                                     AsyncSelectScreenMode(glob, pref);
  1515.                                 }
  1516.                                 break;
  1517.                                 
  1518.                                 case Menu_Mode1:
  1519.                                 case Menu_Mode2:
  1520.                                 case Menu_Mode3:
  1521.                                 {
  1522.                                     if (n->Flags & CHECKED)
  1523.                                     {
  1524.                                         UWORD NewMode = pick - Menu_Mode1;
  1525.                                         if (NewMode != pref->FWMode)
  1526.                                         {
  1527.                                             if (fwdata)
  1528.                                             {
  1529.                                                 (FWDefinitions[pref->FWMode].ExitFireworks)(fwdata);
  1530.                                                 fwdata = NULL;
  1531.                                             }
  1532.                                             
  1533.                                             pref->FWMode = NewMode;
  1534.                                             
  1535.                                             if (!(fwdata = (FWDefinitions[pref->FWMode].InitFireworks)(glob, pref)))
  1536.                                             {
  1537.                                                 Message("Unable to initialize fireworks.", "Oh no");
  1538.                                                 n->Flags &= (~CHECKED);
  1539.                                             }
  1540.                                         }
  1541.                                     }
  1542.                                 }
  1543.                                 break;
  1544.                                 
  1545.                                 case Menu_Double:
  1546.                                 {
  1547.                                     if (n->Flags & CHECKED)
  1548.                                         pref->Flags |= PREFF_DOUBLE;
  1549.                                     else
  1550.                                         pref->Flags &= (~PREFF_DOUBLE);
  1551.                                 }
  1552.                                 break;
  1553.                                 
  1554.                                 case Menu_Release:
  1555.                                 {
  1556.                                     memset(NoteArray,0,sizeof(NoteArray));
  1557.                                     memset(ChanUse  ,0,sizeof(ChanUse  ));
  1558.                                     
  1559.                                     if (fwdata) (FWDefinitions[pref->FWMode].TimePassed)(fwdata);
  1560.                                     if (fwdata) (FWDefinitions[pref->FWMode].ReleaseNotes)(fwdata);
  1561.                                 }
  1562.                                 break;
  1563.                                 
  1564.                                 case Menu_Play:
  1565.                                 {
  1566.                                     AsyncSelectAndPlay(glob, pref);
  1567.                                 };
  1568.                                 break;
  1569.                                 
  1570.                                 case Menu_Stop:
  1571.                                 {
  1572.                                     StopMIDI(glob,pref);
  1573.                                 }
  1574.                                 break;
  1575.                             }
  1576.                             
  1577.                             Co = n->NextSelect;
  1578.                         }
  1579.                         
  1580.                         Watch = SaveWatch;
  1581.                     }
  1582.                 }
  1583.             }
  1584.             
  1585.             if (Active && (gotsignals & SIGBREAKF_CTRL_E))
  1586.             {
  1587.                 MidiMsg msg;
  1588.                 
  1589.                 if (fwdata) (FWDefinitions[pref->FWMode].TimePassed)(fwdata);
  1590.                 
  1591.                 while (GetMidi(glob->midi,&msg))
  1592.                 {
  1593.                     if (noteon(&msg))
  1594.                     {
  1595.                         UBYTE chn  = msg.mm_Status & MS_ChanBits;
  1596.                         UWORD note = msg.mm_Data1;
  1597.                         UWORD cmsk = 1<<chn;
  1598.                         
  1599.                         // if ((Mask & cmsk) && !((NoteArray[note] & Mask)))
  1600.                         // {
  1601.                         // }
  1602.                         
  1603.                         if (!(NoteArray[note] & cmsk))
  1604.                         {
  1605.                             /* Channel wird benutzt */
  1606.                             ChanUse[chn]++;
  1607.                             
  1608.                             NoteArray[note] |= cmsk;
  1609.                             
  1610.                             /* Note angeschlagen */
  1611.                             
  1612.                             if (fwdata) (FWDefinitions[pref->FWMode].NoteOn)(fwdata, chn, note, msg.mm_Data2);
  1613.                         }
  1614.                         
  1615.                     }
  1616.                     else
  1617.                     {
  1618.                         if (noteoff(&msg))
  1619.                         {
  1620.                             UBYTE chn  = msg.mm_Status & MS_ChanBits;
  1621.                             UWORD note = msg.mm_Data1;
  1622.                             UWORD cmsk = 1<<chn;
  1623.                             
  1624.                             if (NoteArray[note] & cmsk)
  1625.                             {
  1626.                                 /* Channel wird nicht mehr benutzt */
  1627.                                 ChanUse[chn]--;
  1628.                                 
  1629.                                 NoteArray[note] &= (~cmsk);
  1630.                                 
  1631.                                 /* Note losgelassen */
  1632.                                 
  1633.                                 if (fwdata) (FWDefinitions[pref->FWMode].NoteOff)(fwdata, chn, note);
  1634.                             }
  1635.                             
  1636.                             // if ((Mask & cmsk) && (!(NoteArray[note] & Mask)))
  1637.                             // {
  1638.                             // }
  1639.                         }
  1640.                         else
  1641.                         {
  1642.                             if (modemsg(&msg))
  1643.                             {
  1644.                                 UBYTE chn  = msg.mm_Status & MS_ChanBits;
  1645.                                 UBYTE mode = msg.mm_Data1;
  1646.                                 UWORD note;
  1647.                                 UWORD cmsk = 1<<chn;
  1648.                                 
  1649.                                 if (mode == MM_AllOff)
  1650.                                 {
  1651.                                     for (note=0;note<128;note++)
  1652.                                     {
  1653.                                         if (NoteArray[note] & cmsk)
  1654.                                         {
  1655.                                             /* Channel wird nicht mehr benuzt */
  1656.                                             ChanUse[chn]--;
  1657.                                             
  1658.                                             if (fwdata) (FWDefinitions[pref->FWMode].NoteOff)(fwdata, chn, note);
  1659.                                             
  1660.                                             NoteArray[note] &= (~cmsk);
  1661.                                         }
  1662.                                         
  1663.                                         // if ((Mask & cmsk) && (!(NoteArray[note] & Mask)))
  1664.                                         // {
  1665.                                         // }
  1666.                                     }
  1667.                                 }
  1668.                             }
  1669.                         }
  1670.                     }
  1671.                 }
  1672.                 
  1673.                 if (Err = GetMidiErr(glob->midi))
  1674.                 {
  1675.                     if (Err & CMEF_MsgErr)            AsyncMessage(glob,ErrTask, "MIDI Error: MsgErr!",NULL);
  1676.                     if (Err & CMEF_BufferFull)        AsyncMessage(glob,ErrTask, "MIDI Error: BufferFull!",NULL);
  1677.                     if (Err & CMEF_SysExFull)        AsyncMessage(glob,ErrTask, "MIDI Error: SysExFull!",NULL);
  1678.                     if (Err & CMEF_ParseMem)        AsyncMessage(glob,ErrTask, "MIDI Error: ParseMem!",NULL);
  1679.                     if (Err & CMEF_RecvErr)            AsyncMessage(glob,ErrTask, "MIDI Error: RecvErr!",NULL);
  1680.                     if (Err & CMEF_RecvOverflow)    AsyncMessage(glob,ErrTask, "MIDI Error: RecvOverflow!",NULL);
  1681.                     if (Err & CMEF_SysExTooBig)        AsyncMessage(glob,ErrTask, "MIDI Error: SysExTooBig!",NULL);
  1682.                 }
  1683.                 
  1684.                 /* (re-)start timer if it isn't running */
  1685.                 if (!TimerActive)
  1686.                 {
  1687.                     /* but only if there is something to display */
  1688.                     if (fwdata) if (!(FWDefinitions[pref->FWMode].IsIdle)(fwdata))
  1689.                     {
  1690.                         glob->treq->tr_node.io_Command = TR_ADDREQUEST;
  1691.                         glob->treq->tr_time.tv_secs  = 0;
  1692.                         glob->treq->tr_time.tv_micro = 1000000 / FPS;
  1693.                         SendIO((struct IORequest*)glob->treq);
  1694.                         TimerActive = TRUE;
  1695.                         Watch = TRUE;
  1696.                         
  1697.                         TitleWindow(glob, "Fireworks [%s]", pref->Link);
  1698.                     }
  1699.                 }
  1700.             }
  1701.             
  1702.             if (Active && (gotsignals & timersig))
  1703.             {
  1704.                 BOOL idle = TRUE;
  1705.                 
  1706.                 IdleCount = 0;
  1707.                 
  1708.                 if (fwdata) (FWDefinitions[pref->FWMode].TimePassed)(fwdata);
  1709.                 if (fwdata) idle = (FWDefinitions[pref->FWMode].IsIdle)(fwdata);
  1710.                 
  1711.                 if (!idle)
  1712.                 {
  1713.                     glob->treq->tr_node.io_Command = TR_ADDREQUEST;
  1714.                     glob->treq->tr_time.tv_secs  = 0;
  1715.                     glob->treq->tr_time.tv_micro = 1000000 / FPS;
  1716.                     SendIO((struct IORequest*)glob->treq);
  1717.                 }
  1718.                 else
  1719.                 {
  1720.                     TimerActive = FALSE;
  1721.                     Watch = FALSE;
  1722.                     SetTaskPri(MyTask, HIGHPRI);
  1723.                     
  1724.                     TitleWindow(glob, "Fireworks [%s] [idle]", pref->Link);
  1725.                 }
  1726.                 
  1727.                 if ((glob->BGBitMap) && (glob->PaintBitMap))
  1728.                 {
  1729.                     BltBitMapRastPort(glob->BGBitMap, 0, 0, &glob->PaintRP, 0, 0, glob->ww, glob->wh, 0xc0);
  1730.                     
  1731.                     if (fwdata) (FWDefinitions[pref->FWMode].DrawFireworks)(fwdata, Mask);
  1732.                     
  1733.                     BltBitMapRastPort(glob->PaintBitMap, 0, 0, glob->Window->RPort, 0, 0, glob->ww, glob->wh, 0xc0);
  1734.                 }
  1735.                 
  1736.                 /* reset task priority if it has
  1737.                    been modified by the watchdog */
  1738.                 if (MyTask->tc_Node.ln_Pri != NORMPRI)
  1739.                 {
  1740.                     SetTaskPri(MyTask, NORMPRI);
  1741.                 }
  1742.             }
  1743.             
  1744.             if (Active && (gotsignals & procsig))
  1745.             {
  1746.                 struct AppMessage *appm;
  1747.                 
  1748.                 while(appm = (struct AppMessage*)GetMsg(& ((struct Process*)MyTask)->pr_MsgPort ))
  1749.                 {
  1750.                     if (appm->am_Type == AMTYPE_APPWINDOW)
  1751.                     {
  1752.                         BOOL SaveWatch = Watch;
  1753.                         struct WBArg *arg = appm->am_ArgList;
  1754.                         ULONG i;
  1755.                         
  1756.                         Watch = FALSE;
  1757.                         
  1758.                         for (i=0 ; i < appm->am_NumArgs ; i++, arg++)
  1759.                         {
  1760.                             BOOL IsPicture = FALSE;
  1761.                             BOOL IsMIDI = FALSE;
  1762.                             
  1763.                             BPTR OldDir;
  1764.                             BPTR lock;
  1765.                             
  1766.                             OldDir = CurrentDir(arg->wa_Lock);
  1767.                             
  1768.                             if (lock = Lock(arg->wa_Name, SHARED_LOCK))
  1769.                             {
  1770.                                 struct DataType *dtn;
  1771.                                 
  1772.                                 if (dtn = ObtainDataTypeA (DTST_FILE, (APTR) lock, NULL))
  1773.                                 {
  1774.                                     if (dtn->dtn_Header->dth_GroupID == GID_PICTURE)
  1775.                                     {
  1776.                                         if (NameFromLock(lock, pref->NewImage, sizeof(pref->NewImage)))
  1777.                                         {
  1778.                                             pref->Image = pref->NewImage;
  1779.                                             IsPicture = TRUE;
  1780.                                         }
  1781.                                     }
  1782.                                     ReleaseDataType (dtn);
  1783.                                 }
  1784.                                 
  1785.                                 if (!IsPicture)
  1786.                                 {
  1787.                                     BPTR dupedlock;
  1788.                                     BPTR file;
  1789.                                     
  1790.                                     if (dupedlock = DupLock(lock))
  1791.                                     {
  1792.                                         if (file = OpenFromLock(dupedlock))
  1793.                                         {
  1794.                                             UBYTE header[20];
  1795.                                             
  1796.                                             if (Read(file, header, sizeof(header)) == sizeof(header))
  1797.                                             {
  1798.                                                 if ( ((header[0] == 'M') &&
  1799.                                                       (header[1] == 'T') &&
  1800.                                                       (header[2] == 'h') &&
  1801.                                                       (header[3] == 'd'))
  1802.                                                     
  1803.                                                     ||
  1804.                                                     
  1805.                                                      ((header[0] == 'X') &&
  1806.                                                       (header[1] == 'P') &&
  1807.                                                       (header[2] == 'K') &&
  1808.                                                       (header[3] == 'F') &&
  1809.                                                       (header[16]== 'M') &&
  1810.                                                       (header[17]== 'T') &&
  1811.                                                       (header[18]== 'h') &&
  1812.                                                       (header[19]== 'd')) )
  1813.                                                 {
  1814.                                                     if (NameFromLock(lock, pref->MIDIFile, sizeof(pref->MIDIFile)))
  1815.                                                     {
  1816.                                                         IsMIDI = TRUE;
  1817.                                                     }
  1818.                                                 }
  1819.                                             }
  1820.                                             Close(file);
  1821.                                         } else UnLock(dupedlock);
  1822.                                     }
  1823.                                 }
  1824.                                 UnLock(lock);
  1825.                             }
  1826.                             CurrentDir(OldDir);
  1827.                             
  1828.                             if (IsPicture) LoadImage(glob, pref);
  1829.                             else
  1830.                                 if (IsMIDI) PlayMIDI(glob, pref);
  1831.                                 else
  1832.                                     AsyncMessage(glob,DropTask, "Please drop only picture objects or MIDI files\ninto the Fireworks window.","Sorry");
  1833.                         }
  1834.                         Watch = SaveWatch;
  1835.                     }
  1836.                     ReplyMsg((struct Message*)appm);
  1837.                 }
  1838.             }
  1839.             
  1840.             if (gotsignals & SIGBREAKF_CTRL_C)
  1841.             {
  1842.                 if (AskAsync(glob))
  1843.                 {
  1844.                     Active = FALSE;
  1845.                     Watch = FALSE;
  1846.                 }
  1847.                 else
  1848.                     AsyncMessage(glob,CloseTask, "Cannot quit yet. Please close all open requesters.","I will");
  1849.             }
  1850.         }
  1851.         
  1852.         RemIntServer(INTB_VERTB, &VertBlank);
  1853.         
  1854.         if (TimerActive)
  1855.         {
  1856.             AbortIO((struct IORequest*)glob->treq);
  1857.             WaitIO((struct IORequest*)glob->treq);
  1858.         }
  1859.         
  1860.         if (fwdata)
  1861.         {
  1862.             (FWDefinitions[pref->FWMode].ExitFireworks)(fwdata);
  1863.             fwdata = NULL;
  1864.         }
  1865.     }
  1866. }
  1867.  
  1868.  
  1869. /*-----------------------------------*/
  1870. /* Linear fireworks (straight lines) */
  1871. /*-----------------------------------*/
  1872.  
  1873. struct LinData
  1874. {
  1875.     struct Globals *glob;
  1876.     struct Prefs *pref;
  1877.     
  1878.     ULONG curtime;
  1879.     
  1880.     WORD centx, centy;
  1881.     WORD divx, divy;
  1882.     
  1883.     struct MinList CrackerList;
  1884.     
  1885.     WORD fxtab[128], fytab[128];
  1886. };
  1887.  
  1888. #define SCALE 1024
  1889.  
  1890. /* the firecrackers */
  1891.  
  1892. struct LinearCracker
  1893. {
  1894.     struct Node        cr_node;
  1895.     UBYTE            cr_chn;            /* 0 - 15  */
  1896.     UBYTE            cr_note;        /* 0 - 127 */
  1897.     UBYTE            cr_vel;            /* 0 - 127 */
  1898.     
  1899.     LONG            cr_starttime;        /* time stamp of note on */
  1900.     LONG            cr_stoptime;        /* time stamp of note off */
  1901.     UWORD            cr_savedlifetime;    /* lifetime when ray hit border */
  1902.     
  1903.     WORD            cr_fx;            /* -SCALE to SCALE equals -1 to -1 */
  1904.     WORD            cr_fy;            /* -SCALE to SCALE equals -1 to -1 */
  1905. };
  1906.  
  1907. APTR Lin_InitFireworks(struct Globals *glob, struct Prefs *pref)
  1908. {
  1909.     struct LinData *ld = NULL;
  1910.     UWORD i;
  1911.     
  1912.     if (ld = AllocVec(sizeof(struct LinData), MEMF_ANY|MEMF_CLEAR))
  1913.     {
  1914.         ld->glob = glob;
  1915.         ld->pref = pref;
  1916.         
  1917.         NewList((struct List*)&ld->CrackerList);
  1918.         
  1919.         /* pre-calculate angles of all possible 128 notes */
  1920.         for (i = 0 ; i < 128 ; i++)
  1921.         {
  1922.             float angle = PI - (float)i/127 * PI;
  1923.             
  1924.             ld->fxtab[i] = SCALE * cos(angle);
  1925.             ld->fytab[i] = SCALE * sin(angle);
  1926.         }
  1927.         
  1928.         Lin_RethinkWindow((APTR)ld);
  1929.         
  1930.         GetTimeDelta();            /* initialize delta counter */
  1931.         ld->curtime = 0;        /* start at time counter 0 */
  1932.     }
  1933.     
  1934.     return((APTR)ld);
  1935. }
  1936.  
  1937. void Lin_RethinkWindow(APTR data)
  1938. {
  1939.     struct LinData *ld = (struct LinData*) data;
  1940.     struct Globals *glob = ld->glob;
  1941.     
  1942.     /* Calculate ray scaling factors */
  1943.     ld->divx  = SCALE * MAXCOORD / (glob->ww);
  1944.     ld->divy  = SCALE * MAXCOORD / (glob->wh);
  1945.     ld->centx = CENTER_X * (glob->ww) / MAXCOORD;
  1946.     ld->centy = CENTER_Y * (glob->wh) / MAXCOORD;
  1947. }
  1948.  
  1949. void Lin_TimePassed(APTR data)
  1950. {
  1951.     struct LinData *ld = (struct LinData*) data;
  1952.     
  1953.     ld->curtime += GetTimeDelta();
  1954. }
  1955.  
  1956. BOOL Lin_IsIdle(APTR data)
  1957. {
  1958.     struct LinData *ld = (struct LinData*) data;
  1959.     
  1960.     if (IsListEmpty((struct List*)&ld->CrackerList))
  1961.         return(TRUE);
  1962.     else
  1963.         return(FALSE);
  1964. }
  1965.  
  1966. void Lin_DrawFireworks(APTR data, UWORD Mask)
  1967. {
  1968.     struct LinData *ld = (struct LinData*) data;
  1969.     struct LinearCracker *cr, *ncr;
  1970.     struct Globals *glob = ld->glob;
  1971.     struct Prefs *pref = ld->pref;
  1972.     
  1973.     UWORD lifetime;
  1974.     UWORD deathtime;
  1975.     WORD sx1, sy1;
  1976.     WORD sx2, sy2;
  1977.     LONG lastpen = -1, newpen;
  1978.     
  1979.     for ( cr = (struct LinearCracker*) ld->CrackerList.mlh_Head ;
  1980.           ncr = (struct LinearCracker*) cr->cr_node.ln_Succ ;
  1981.           cr = ncr )
  1982.     {
  1983.         /* get the ray's lifetime information */
  1984.         
  1985.         if (cr->cr_savedlifetime == 0xffff)
  1986.             lifetime = (UWORD)(ld->curtime - cr->cr_starttime);
  1987.         else
  1988.             lifetime = cr->cr_savedlifetime;
  1989.         
  1990.         /* calculate ray starting points */
  1991.         sx1 = ld->centx + cr->cr_fx *  lifetime / ld->divx;
  1992.         sy1 = ld->centy - cr->cr_fy *  lifetime / ld->divy;
  1993.         
  1994.         if (cr->cr_savedlifetime == 0xffff)
  1995.         {
  1996.             if ((sx1 >= glob->ww) || (sy1 >= glob->wh) || (sx1 < 0) || (sy1 < 0))
  1997.             {
  1998.                 /* Start of ray hit window borders */
  1999.                 /* save the time this happened to prevent */
  2000.                 /* the ray from growing longer than */
  2001.                 /* graphic's clipping can handle safely */
  2002.                 cr->cr_savedlifetime = lifetime;
  2003.             }
  2004.         }
  2005.         
  2006.         /* has ray already been stopped by a note off? */
  2007.         if (cr->cr_stoptime == -1)
  2008.         {
  2009.             /* no, still emmitting from the centre */
  2010.             sx2 = ld->centx;
  2011.             sy2 = ld->centy;
  2012.         }
  2013.         else
  2014.         {
  2015.             /* get the time when the note off occured */
  2016.             deathtime = (UWORD)(ld->curtime - cr->cr_stoptime);
  2017.             
  2018.             /* is the ray just a dot? */
  2019.             if (lifetime == deathtime)
  2020.             {
  2021.                 sx2 = sx1;
  2022.                 sy2 = sy1;
  2023.             }
  2024.             else
  2025.             {
  2026.                 /* calculate ray ending points */
  2027.                 sy2 = ld->centy - cr->cr_fy * deathtime / ld->divy;
  2028.                 sx2 = ld->centx + cr->cr_fx * deathtime / ld->divx;
  2029.             }
  2030.         }
  2031.         
  2032.         /* see if the ray has disappeared */
  2033.         /* or exceeded his maximum lifetime of 60 seconds */
  2034.         if ((sx2 >= glob->ww) || (sy2 >= glob->wh) || (sx2 < 0) || (sy2 < 0) ||
  2035.             lifetime  > 60000 )
  2036.         {
  2037.             Remove((struct Node*)cr);
  2038.             FreePooled(glob->NotePool,cr,sizeof(struct LinearCracker));
  2039.         }
  2040.         else
  2041.         {
  2042.             /* display this channel ? */
  2043.             if ((1<<cr->cr_chn) & Mask)
  2044.             {
  2045.                 /* change pen if necessary */
  2046.                 newpen = glob->PenArray[Channelpens+cr->cr_chn];
  2047.                 if (lastpen != newpen)
  2048.                 {
  2049.                     SetAPen(&glob->PaintRP, newpen);
  2050.                     lastpen = newpen;
  2051.                 }
  2052.                 
  2053.                 /* draw the ray */
  2054.                 Move(&glob->PaintRP, sx1, sy1);
  2055.                 Draw(&glob->PaintRP, sx2, sy2);
  2056.                 
  2057.                 if (pref->Flags & PREFF_DOUBLE)
  2058.                 {
  2059.                     WORD dx, dy;
  2060.                     dx = sx2 - sx1; if (dx<0) dx=-dx;
  2061.                     dy = sy2 - sy1; if (dy<0) dy=-dy;
  2062.                     
  2063.                     if (dy >= dx)
  2064.                     {
  2065.                         Move(&glob->PaintRP, sx1+1, sy1);
  2066.                         Draw(&glob->PaintRP, sx2+1, sy2);
  2067.                     }
  2068.                     else
  2069.                     {
  2070.                         Move(&glob->PaintRP, sx1, sy1+1);
  2071.                         Draw(&glob->PaintRP, sx2, sy2+1);
  2072.                     }
  2073.                 }
  2074.             }
  2075.         }
  2076.     }
  2077. }
  2078.  
  2079. void Lin_NoteOn(APTR data, UBYTE chn, UBYTE note, UBYTE vel)
  2080. {
  2081.     struct LinData *ld = (struct LinData*) data;
  2082.     struct Globals *glob = ld->glob;
  2083.     struct LinearCracker *cr;
  2084.     
  2085.     if (cr = AllocPooled(glob->NotePool, sizeof(struct LinearCracker)))
  2086.     {
  2087.         cr->cr_node.ln_Pri = chn;
  2088.         
  2089.         cr->cr_chn  = chn;
  2090.         cr->cr_note = note;
  2091.         cr->cr_vel  = vel;
  2092.         
  2093.         cr->cr_starttime = ld->curtime;
  2094.         cr->cr_stoptime  = -1;
  2095.         cr->cr_savedlifetime = 0xffff;
  2096.         
  2097.         cr->cr_fx = ld->fxtab[note] * cr->cr_vel / 127;
  2098.         cr->cr_fy = ld->fytab[note] * cr->cr_vel / 127;
  2099.         
  2100.         /* sorted by channel num to speed up painting */
  2101.         Enqueue((struct List*)&ld->CrackerList, (struct Node*)cr);
  2102.     }
  2103. }
  2104.  
  2105. void Lin_NoteOff(APTR data, UBYTE chn, UBYTE note)
  2106. {
  2107.     struct LinData *ld = (struct LinData*) data;
  2108.     struct LinearCracker *cr, *ncr;
  2109.     
  2110.     for ( cr = (struct LinearCracker*) ld->CrackerList.mlh_Head ;
  2111.           ncr = (struct LinearCracker*) cr->cr_node.ln_Succ ;
  2112.           cr = ncr )
  2113.     {
  2114.         if ( (cr->cr_chn  == chn ) &&
  2115.              (cr->cr_note == note) &&
  2116.              (cr->cr_stoptime == -1) )
  2117.         {
  2118.             cr->cr_stoptime = ld->curtime;
  2119.             break;
  2120.         }
  2121.     }
  2122. }
  2123.  
  2124. void Lin_ReleaseNotes(APTR data)
  2125. {
  2126.     struct LinData *ld = (struct LinData*) data;
  2127.     struct LinearCracker *cr, *ncr;
  2128.     
  2129.     for ( cr = (struct LinearCracker*) ld->CrackerList.mlh_Head ;
  2130.           ncr = (struct LinearCracker*) cr->cr_node.ln_Succ ;
  2131.           cr = ncr )
  2132.     {
  2133.         if (cr->cr_stoptime == -1) cr->cr_stoptime = ld->curtime;
  2134.     }
  2135. }
  2136.  
  2137. void Lin_FreeNoteData(APTR data)
  2138. {
  2139.     struct LinData *ld = (struct LinData*) data;
  2140.     struct Globals *glob = ld->glob;
  2141.     struct LinearCracker *cr, *ncr;
  2142.     
  2143.     for ( cr = (struct LinearCracker*) ld->CrackerList.mlh_Head ;
  2144.           ncr = (struct LinearCracker*) cr->cr_node.ln_Succ ;
  2145.           cr = ncr )
  2146.     {
  2147.         Remove((struct Node*)cr);
  2148.         FreePooled(glob->NotePool,cr,sizeof(struct LinearCracker));
  2149.     }
  2150. }
  2151.  
  2152. void Lin_ExitFireworks(APTR data)
  2153. {
  2154.     struct LinData *ld = (struct LinData*) data;
  2155.     
  2156.     if (ld)
  2157.     {
  2158.         Lin_FreeNoteData(data);
  2159.         
  2160.         FreeVec(ld);
  2161.     }
  2162. }
  2163.  
  2164.  
  2165.  
  2166. /*------------------------------------------*/
  2167. /* Parabolic fireworks (gravity simulation) */
  2168. /*------------------------------------------*/
  2169.  
  2170. #define K 10
  2171. #define MAXLIFETIME (K*MAXCOORD)
  2172.  
  2173. struct ParData
  2174. {
  2175.     struct Globals *glob;
  2176.     struct Prefs *pref;
  2177.     
  2178.     ULONG curtime;
  2179.     
  2180.     WORD centx, centy;
  2181.     WORD divx, divy;
  2182.     UWORD winscale;
  2183.     
  2184.     struct MinList CrackerList;
  2185.     
  2186.     WORD fxtab[128], fytab[128];
  2187.     WORD  parabtable[MAXLIFETIME];    /* parabolic flight path */
  2188.     UWORD parabskip[MAXLIFETIME];    /* info for painting flight paths */
  2189. };
  2190.  
  2191. #define SCALE 1024
  2192.  
  2193. /* the firecrackers */
  2194.  
  2195. struct ParabolicCracker
  2196. {
  2197.     struct Node        cr_node;
  2198.     UBYTE            cr_chn;            /* 0 - 15  */
  2199.     UBYTE            cr_note;        /* 0 - 127 */
  2200.     UBYTE            cr_vel;            /* 0 - 127 */
  2201.     
  2202.     LONG            cr_starttime;        /* time stamp of note on */
  2203.     LONG            cr_stoptime;        /* time stamp of note off */
  2204.     
  2205.     WORD            cr_fx;            /* -SCALE to SCALE equals -1 to -1 */
  2206.     WORD            cr_fy;            /* -SCALE to SCALE equals -1 to -1 */
  2207.     
  2208.     UWORD            cr_offset;        /* offset to lifetime */
  2209.     WORD            cr_coordoffset;    /* offset to coordinate */
  2210.     
  2211.     UWORD            cr_multiplier;    /* time skip multiplier (-SCALE to SCALE) */
  2212. };
  2213.  
  2214. APTR Par_InitFireworks(struct Globals *glob, struct Prefs *pref)
  2215. {
  2216.     struct ParData *pd = NULL;
  2217.     UWORD i;
  2218.     UWORD lt;
  2219.     WORD val;
  2220.     
  2221.     if (pd = AllocVec(sizeof(struct ParData), MEMF_ANY|MEMF_CLEAR))
  2222.     {
  2223.         pd->glob = glob;
  2224.         pd->pref = pref;
  2225.         
  2226.         NewList((struct List*)&pd->CrackerList);
  2227.         
  2228.         SetPointer(glob->Window, WaitPointer, 16, 16, -6, 0);
  2229.         
  2230.         /* pre-calculate angles of all possible 128 notes */
  2231.         for (i = 0 ; i < 128 ; i++)
  2232.         {
  2233.             float angle = PI - (float)i/127 * PI;
  2234.             
  2235.             pd->fxtab[i] = SCALE * cos(angle);
  2236.             pd->fytab[i] = SCALE * sin(angle);
  2237.         }
  2238.         
  2239.         val = -(MAXLIFETIME/2);
  2240.         
  2241.         for (lt=0 ; lt <= MAXLIFETIME/2 ; lt++, val++)
  2242.         {
  2243.             pd->parabtable[lt] = pd->parabtable[MAXLIFETIME-1-lt] =
  2244.                 (LONG)(val * val) / ((MAXLIFETIME*MAXLIFETIME/4) / (K * MAXCOORD / 4));
  2245.         }
  2246.         
  2247.         if (pref->FWMode == ParabolicMode2)
  2248.         {
  2249.             val = -(MAXLIFETIME/2);
  2250.             
  2251.             for (lt=0 ; lt <= MAXLIFETIME/2 ; )
  2252.             {
  2253.                 UWORD s = (64.0 * pow(1+4*(float)(val*val)/(MAXLIFETIME*MAXLIFETIME/4),1.5));
  2254.                 
  2255.                 for (i=0; i<16; i++)
  2256.                 {
  2257.                     pd->parabskip[lt] = pd->parabskip[MAXLIFETIME-1-lt] = s;
  2258.                     lt++; val++;
  2259.                 }
  2260.             }
  2261.         }
  2262.         
  2263.         ClearPointer(glob->Window);
  2264.         
  2265.         Par_RethinkWindow((APTR)pd);
  2266.         
  2267.         GetTimeDelta();            /* initialize delta counter */
  2268.         pd->curtime = 0;        /* start at time counter 0 */
  2269.     }
  2270.     
  2271.     return((APTR)pd);
  2272. }
  2273.  
  2274. void Par_RethinkWindow(APTR data)
  2275. {
  2276.     struct ParData *pd = (struct ParData*) data;
  2277.     struct Globals *glob = pd->glob;
  2278.     
  2279.     /* Calculate ray scaling factors */
  2280.     pd->divx  = SCALE * MAXCOORD / (glob->ww);
  2281.     pd->divy  =         MAXCOORD / (glob->wh);
  2282.     pd->centx = CENTER_X * (glob->ww) / MAXCOORD;
  2283.     pd->centy = CENTER_Y * (glob->wh) / MAXCOORD;
  2284.     
  2285.     pd->winscale = SCALE * (3 * MAXCOORD) / (glob->ww + glob->wh + MAXCOORD);
  2286. }
  2287.  
  2288. void Par_TimePassed(APTR data)
  2289. {
  2290.     struct ParData *pd = (struct ParData*) data;
  2291.     
  2292.     pd->curtime += GetTimeDelta();
  2293. }
  2294.  
  2295. BOOL Par_IsIdle(APTR data)
  2296. {
  2297.     struct ParData *pd = (struct ParData*) data;
  2298.     
  2299.     if (IsListEmpty((struct List*)&pd->CrackerList))
  2300.         return(TRUE);
  2301.     else
  2302.         return(FALSE);
  2303. }
  2304.  
  2305. void Par_DrawFireworks(APTR data, UWORD Mask)
  2306. {
  2307.     struct ParData *pd = (struct ParData*) data;
  2308.     struct ParabolicCracker *cr, *ncr;
  2309.     struct Globals *glob = pd->glob;
  2310.     struct Prefs *pref = pd->pref;
  2311.     
  2312.     UWORD lifetime;
  2313.     UWORD lt;
  2314.     WORD sx1, sy1;
  2315.     LONG lastpen = -1, newpen;
  2316.     
  2317.     for ( cr = (struct ParabolicCracker*) pd->CrackerList.mlh_Head ;
  2318.           ncr = (struct ParabolicCracker*) cr->cr_node.ln_Succ ;
  2319.           cr = ncr )
  2320.     {
  2321.         /* get the pixel's lifetime information */
  2322.         
  2323.         lifetime = (UWORD)(pd->curtime - cr->cr_starttime);
  2324.         lt = lifetime + cr->cr_offset;
  2325.         if (lt >= MAXLIFETIME) lt = MAXLIFETIME-1;
  2326.         
  2327.         /* calculate pixel coordinate */
  2328.         sx1 = pd->centx + cr->cr_fx * lifetime          / pd->divx;
  2329.         sy1 = pd->centy
  2330.             + (pd->parabtable[lt] - cr->cr_coordoffset) / pd->divy;
  2331.         
  2332.         /* see if the pixel has disappeared */
  2333.         /* or exceeded his maximum lifetime */
  2334.         if ( (sx1 >= glob->ww) || (sy1 >= glob->wh) || (sx1 < 0) ||
  2335.              lt >= (MAXLIFETIME-1) )
  2336.         {
  2337.             Remove((struct Node*)cr);
  2338.             FreePooled(glob->NotePool,cr,sizeof(struct ParabolicCracker));
  2339.         }
  2340.         else
  2341.         {
  2342.             /* display this channel ? */
  2343.             if ((1<<cr->cr_chn) & Mask)
  2344.             {
  2345.                 /* change pen if necessary */
  2346.                 newpen = glob->PenArray[Channelpens+cr->cr_chn];
  2347.                 if (lastpen != newpen)
  2348.                 {
  2349.                     SetAPen(&glob->PaintRP, newpen);
  2350.                     lastpen = newpen;
  2351.                 }
  2352.                 
  2353.                 if ((sx1 >= 0) && (sy1 >= 0))
  2354.                 {
  2355.                     struct Layer *SaveLayer = glob->PaintRP.Layer;
  2356.                     glob->PaintRP.Layer = NULL;
  2357.                     
  2358.                     if (!(pref->Flags & PREFF_DOUBLE))
  2359.                     {
  2360.                         if ((sx1 < (glob->ww  )) && (sy1 < (glob->wh  )))
  2361.                         {
  2362.                             /* draw the pixel */
  2363.                             WritePixel(&glob->PaintRP, sx1, sy1);
  2364.                         }
  2365.                     }
  2366.                     else
  2367.                     {
  2368.                         if ((sx1 < (glob->ww-1)) && (sy1 < (glob->wh-1)))
  2369.                         {
  2370.                             WritePixel(&glob->PaintRP, sx1  , sy1  );
  2371.                             WritePixel(&glob->PaintRP, sx1+1, sy1  );
  2372.                             WritePixel(&glob->PaintRP, sx1  , sy1+1);
  2373.                             WritePixel(&glob->PaintRP, sx1+1, sy1+1);
  2374.                         }
  2375.                     }
  2376.                     glob->PaintRP.Layer = SaveLayer;
  2377.                 }
  2378.             }
  2379.         }
  2380.     }
  2381. }
  2382.  
  2383. void Par_NoteOn(APTR data, UBYTE chn, UBYTE note, UBYTE vel)
  2384. {
  2385.     struct ParData *pd = (struct ParData*) data;
  2386.     struct Globals *glob = pd->glob;
  2387.     struct ParabolicCracker *cr;
  2388.     WORD absfx;
  2389.     
  2390.     if (cr = AllocPooled(glob->NotePool, sizeof(struct ParabolicCracker)))
  2391.     {
  2392.         cr->cr_node.ln_Pri = chn;
  2393.         
  2394.         cr->cr_chn  = chn;
  2395.         cr->cr_note = note;
  2396.         cr->cr_vel  = vel;
  2397.         
  2398.         cr->cr_starttime = pd->curtime;
  2399.         cr->cr_stoptime  = -1;
  2400.         cr->cr_fx = pd->fxtab[note] * cr->cr_vel / 127;
  2401.         cr->cr_fy = pd->fytab[note] * cr->cr_vel / 127;
  2402.         
  2403.         cr->cr_offset      = (MAXLIFETIME/2) * (SCALE-cr->cr_fy) / SCALE;
  2404.         cr->cr_coordoffset = pd->parabtable[cr->cr_offset];
  2405.         
  2406.         absfx = cr->cr_fx;
  2407.         if (absfx < 0) absfx = -absfx;
  2408.         
  2409.         cr->cr_multiplier = (SCALE - absfx);
  2410.         
  2411.         /* sorted by channel num to speed up painting */
  2412.         Enqueue((struct List*)&pd->CrackerList, (struct Node*)cr);
  2413.     }
  2414. }
  2415.  
  2416. void Par_NoteOff(APTR data, UBYTE chn, UBYTE note)
  2417. {
  2418.     struct ParData *pd = (struct ParData*) data;
  2419.     struct ParabolicCracker *cr, *ncr;
  2420.     
  2421.     for ( cr = (struct ParabolicCracker*) pd->CrackerList.mlh_Head ;
  2422.           ncr = (struct ParabolicCracker*) cr->cr_node.ln_Succ ;
  2423.           cr = ncr )
  2424.     {
  2425.         if ( (cr->cr_chn  == chn ) &&
  2426.              (cr->cr_note == note) &&
  2427.              (cr->cr_stoptime == -1) )
  2428.         {
  2429.             cr->cr_stoptime = pd->curtime;
  2430.             break;
  2431.         }
  2432.     }
  2433. }
  2434.  
  2435. void Par_ReleaseNotes(APTR data)
  2436. {
  2437.     struct ParData *pd = (struct ParData*) data;
  2438.     struct ParabolicCracker *cr, *ncr;
  2439.     
  2440.     for ( cr = (struct ParabolicCracker*) pd->CrackerList.mlh_Head ;
  2441.           ncr = (struct ParabolicCracker*) cr->cr_node.ln_Succ ;
  2442.           cr = ncr )
  2443.     {
  2444.         if (cr->cr_stoptime == -1) cr->cr_stoptime = pd->curtime;
  2445.     }
  2446. }
  2447.  
  2448. void Par_FreeNoteData(APTR data)
  2449. {
  2450.     struct ParData *pd = (struct ParData*) data;
  2451.     struct Globals *glob = pd->glob;
  2452.     struct ParabolicCracker *cr, *ncr;
  2453.     
  2454.     for ( cr = (struct ParabolicCracker*) pd->CrackerList.mlh_Head ;
  2455.           ncr = (struct ParabolicCracker*) cr->cr_node.ln_Succ ;
  2456.           cr = ncr )
  2457.     {
  2458.         Remove((struct Node*)cr);
  2459.         FreePooled(glob->NotePool,cr,sizeof(struct ParabolicCracker));
  2460.     }
  2461. }
  2462.  
  2463. void Par_ExitFireworks(APTR data)
  2464. {
  2465.     struct ParData *pd = (struct ParData*) data;
  2466.     
  2467.     if (pd)
  2468.     {
  2469.         Par_FreeNoteData(data);
  2470.         
  2471.         FreeVec(pd);
  2472.     }
  2473. }
  2474.  
  2475.  
  2476.  
  2477. /*-------------------------------------*/
  2478. /* Parabolic rays (gravity simulation) */
  2479. /*-------------------------------------*/
  2480.  
  2481. void Par_DrawFireworks2(APTR data, UWORD Mask)
  2482. {
  2483.     struct ParData *pd = (struct ParData*) data;
  2484.     struct ParabolicCracker *cr, *ncr;
  2485.     struct Globals *glob = pd->glob;
  2486.     struct Prefs *pref = pd->pref;
  2487.     
  2488.     UWORD lifetime;
  2489.     UWORD deathtime;
  2490.     UWORD lt, dt, t;
  2491.     WORD sx1, sy1;
  2492.     WORD sx2, sy2;
  2493.     WORD dx, dy;
  2494.     LONG lastpen = -1, newpen;
  2495.     
  2496.     for ( cr = (struct ParabolicCracker*) pd->CrackerList.mlh_Head ;
  2497.           ncr = (struct ParabolicCracker*) cr->cr_node.ln_Succ ;
  2498.           cr = ncr )
  2499.     {
  2500.         /* get the parabolic ray's lifetime information */
  2501.         
  2502.         lifetime = (UWORD)(pd->curtime - cr->cr_starttime);
  2503.         lt = lifetime + cr->cr_offset;
  2504.         if (lt >= MAXLIFETIME) lt = MAXLIFETIME-1;
  2505.         
  2506.         /* has ray already been stopped by a note off? */
  2507.         if (cr->cr_stoptime == -1)
  2508.         {
  2509.             deathtime = 0;
  2510.         }
  2511.         else
  2512.         {
  2513.             deathtime = (UWORD)(pd->curtime - cr->cr_stoptime);
  2514.         }
  2515.         
  2516.         dt = deathtime + cr->cr_offset;
  2517.         if (dt >= MAXLIFETIME) dt = MAXLIFETIME-1;
  2518.         
  2519.         /* calculate parabolic ray coordinate */
  2520.         sx1 = pd->centx + cr->cr_fx * deathtime         / pd->divx;
  2521.         sy1 = pd->centy
  2522.             + (pd->parabtable[dt] - cr->cr_coordoffset) / pd->divy;
  2523.         
  2524.         /* see if the parabolic ray has disappeared */
  2525.         /* or exceeded his maximum lifetime */
  2526.         if ( (sx1 >= glob->ww) || (sy1 >= glob->wh) || (sx1 < 0) ||
  2527.              dt >= (MAXLIFETIME-1) )
  2528.         {
  2529.             Remove((struct Node*)cr);
  2530.             FreePooled(glob->NotePool,cr,sizeof(struct ParabolicCracker));
  2531.         }
  2532.         else
  2533.         {
  2534.             /* display this channel ? */
  2535.             if ((1<<cr->cr_chn) & Mask)
  2536.             {
  2537.                 /* change pen if necessary */
  2538.                 newpen = glob->PenArray[Channelpens+cr->cr_chn];
  2539.                 if (lastpen != newpen)
  2540.                 {
  2541.                     SetAPen(&glob->PaintRP, newpen);
  2542.                     lastpen = newpen;
  2543.                 }
  2544.                 
  2545.                 if (lifetime == deathtime)
  2546.                 {
  2547.                     /* This handles the ray like a pixel */
  2548.                     
  2549.                     if ((sx1 >= 0) && (sy1 >= 0))
  2550.                     {
  2551.                         struct Layer *SaveLayer = glob->PaintRP.Layer;
  2552.                         glob->PaintRP.Layer = NULL;
  2553.                         
  2554.                         if (!(pref->Flags & PREFF_DOUBLE))
  2555.                         {
  2556.                             if ((sx1 < (glob->ww  )) && (sy1 < (glob->wh  )))
  2557.                             {
  2558.                                 /* draw the pixel */
  2559.                                 WritePixel(&glob->PaintRP, sx1, sy1);
  2560.                             }
  2561.                         }
  2562.                         else
  2563.                         {
  2564.                             if ((sx1 < (glob->ww-1)) && (sy1 < (glob->wh-1)))
  2565.                             {
  2566.                                 WritePixel(&glob->PaintRP, sx1  , sy1  );
  2567.                                 WritePixel(&glob->PaintRP, sx1+1, sy1  );
  2568.                                 WritePixel(&glob->PaintRP, sx1  , sy1+1);
  2569.                                 WritePixel(&glob->PaintRP, sx1+1, sy1+1);
  2570.                             }
  2571.                         }
  2572.                         glob->PaintRP.Layer = SaveLayer;
  2573.                     }
  2574.                 }
  2575.                 else
  2576.                 {
  2577.                     BOOL Clean = FALSE;
  2578.                     BOOL Invisible = FALSE;
  2579.                     struct Layer *SaveLayer = glob->PaintRP.Layer;
  2580.                     
  2581.                     Move(&glob->PaintRP, sx1, sy1);
  2582.                     
  2583.                     for ( t=dt ; t<lt ; )
  2584.                     {
  2585.                         UWORD skip = pd->parabskip[t]
  2586.                                      * cr->cr_multiplier / SCALE
  2587.                                      * pd->winscale      / SCALE;
  2588.                         
  2589.                         if (skip == 0) skip = 1;
  2590.                         
  2591.                         deathtime += skip;
  2592.                         t         += skip;
  2593.                         
  2594.                         if (t>lt)
  2595.                         {
  2596.                             t=lt;
  2597.                             deathtime=lifetime;
  2598.                         }
  2599.                         
  2600.                         if (sy1 < 0) Invisible = TRUE;
  2601.                         
  2602.                         if ((sx1 >= (glob->ww)) || (sx1 < 0) || (sy1 > (glob->wh)))
  2603.                             break;
  2604.                         
  2605.                         sx2 = sx1;
  2606.                         sy2 = sy1;
  2607.                         
  2608.                         sx1 = pd->centx + cr->cr_fx * deathtime        / pd->divx;
  2609.                         sy1 = pd->centy
  2610.                             + (pd->parabtable[t] - cr->cr_coordoffset) / pd->divy;
  2611.                         
  2612.                         if (Invisible)
  2613.                         {
  2614.                             if (sy1 >= 0)
  2615.                             {
  2616.                                 Move(&glob->PaintRP, sx2, sy2);
  2617.                                 Invisible = FALSE;
  2618.                             }
  2619.                         }
  2620.                         
  2621.                         if (!Invisible)
  2622.                         {
  2623.                             if ((sx1 >= 0) && (sx1 < (glob->ww)) &&
  2624.                                 (sy1 >= 0) && (sy1 < (glob->wh)) )
  2625.                             {
  2626.                                 if (Clean)
  2627.                                     glob->PaintRP.Layer = NULL;
  2628.                                 else
  2629.                                     Clean = TRUE;
  2630.                             }
  2631.                             else
  2632.                             {
  2633.                                 if (Clean)
  2634.                                 {
  2635.                                     glob->PaintRP.Layer = SaveLayer;
  2636.                                     Clean = FALSE;
  2637.                                 }
  2638.                             }
  2639.                             
  2640.                             Draw(&glob->PaintRP, sx1, sy1);
  2641.                             //WritePixel(&glob->PaintRP, sx1, sy1);
  2642.                             
  2643.                             if (pref->Flags & PREFF_DOUBLE)
  2644.                             {
  2645.                                 struct Layer *Save2 = glob->PaintRP.Layer;
  2646.                                 
  2647.                                 if ((sx1 >= 0) && (sx2 >=0) &&
  2648.                                     (sy1 >= 0) && (sy2 >=0) &&
  2649.                                     (sx1 < (glob->ww-1)) && (sy1 < (glob->wh-1)) &&
  2650.                                     (sx2 < (glob->ww-1)) && (sy2 < (glob->wh-1)))
  2651.                                 {
  2652.                                     glob->PaintRP.Layer = NULL;
  2653.                                 }
  2654.                                 else
  2655.                                 {
  2656.                                     glob->PaintRP.Layer = SaveLayer;
  2657.                                 }
  2658.                                 
  2659.                                 dx = sx2 - sx1; if (dx<0) dx=-dx;
  2660.                                 dy = sy2 - sy1; if (dy<0) dy=-dy;
  2661.                                 
  2662.                                 if (dy >= dx)
  2663.                                 {
  2664.                                     Move(&glob->PaintRP, sx2+1, sy2);
  2665.                                     Draw(&glob->PaintRP, sx1+1, sy1);
  2666.                                 }
  2667.                                 else
  2668.                                 {
  2669.                                     Move(&glob->PaintRP, sx2, sy2+1);
  2670.                                     Draw(&glob->PaintRP, sx1, sy1+1);
  2671.                                 }
  2672.                                 
  2673.                                 Move(&glob->PaintRP, sx1, sy1);
  2674.                                 
  2675.                                 glob->PaintRP.Layer = Save2;
  2676.                             }
  2677.                         }
  2678.                     }
  2679.                     
  2680.                     glob->PaintRP.Layer = SaveLayer;
  2681.                 }
  2682.             }
  2683.         }
  2684.     }
  2685. }
  2686.  
  2687.  
  2688.  
  2689. /*----------------------------------------*/
  2690. /* VBR Interrupt handler (Watchdog timer) */
  2691. /*----------------------------------------*/
  2692.  
  2693. int __interrupt __saveds VBlankInterface( void )
  2694. {
  2695.     if (Watch)
  2696.     {
  2697.         if (IdleCount++ >= (50/MIN_FPS))
  2698.         {
  2699.             SetTaskPri(MyTask, HIGHPRI);
  2700.             IdleCount = 0;
  2701.         }
  2702.     }
  2703.     return 0;                      /* server chain continues */
  2704. }
  2705.  
  2706.  
  2707.  
  2708. /*------------------------------------*/
  2709. /* Asynchronously select a screenmode */
  2710. /*------------------------------------*/
  2711.  
  2712. struct SMData
  2713. {
  2714.     struct Message Message;
  2715.     struct Globals *glob;
  2716.     struct Prefs *pref;
  2717. };
  2718.  
  2719. void SyncSelectScreenMode(struct Globals *glob, struct Prefs *pref)
  2720. {
  2721.     if (SelectScreenMode(glob, pref, &glob->ScreenModeRQ))
  2722.     {
  2723.         pref->Flags |= PREFF_FULLSCREEN;
  2724.         glob->GUIRefresh = TRUE;
  2725.         Signal(MyTask, SIGBREAKF_CTRL_E);    /* wake up main task */
  2726.     }
  2727. }
  2728.  
  2729. void __saveds AsyncSelectScreenModeTask(void)
  2730. {
  2731.     struct SMData *smd;
  2732.     struct Process *MyProc = (struct Process*)FindTask(NULL);
  2733.     struct Globals *glob;
  2734.     struct Prefs *pref;
  2735.     
  2736.     WaitPort(&MyProc->pr_MsgPort);
  2737.     if (smd = (struct SMData*)GetMsg(&MyProc->pr_MsgPort))
  2738.     {
  2739.         glob = smd->glob;
  2740.         pref = smd->pref;
  2741.         SyncSelectScreenMode(glob,pref);
  2742.         
  2743.         FreeVec(smd);
  2744.         
  2745.         Forbid();
  2746.         FreeAsync(glob, ScreenTask);
  2747.     }
  2748. }
  2749.  
  2750. void AsyncSelectScreenMode(struct Globals *glob, struct Prefs *pref)
  2751. {
  2752.     struct SMData *smd;
  2753.     struct Process *proc;
  2754.     BOOL Success = FALSE;
  2755.     
  2756.     if (AllocAsync(glob, ScreenTask))
  2757.     {
  2758.         if (smd = AllocVec(sizeof(struct SMData), MEMF_ANY|MEMF_CLEAR))
  2759.         {
  2760.             if (proc = CreateNewProcTags(
  2761.                     NP_Entry, &AsyncSelectScreenModeTask,
  2762.                     NP_Name, "Fireworks screenmode selection task",
  2763.                     NP_Priority, 0,
  2764.                     NP_Input, Input(),
  2765.                     NP_Output, Output(),
  2766.                     NP_CloseInput, FALSE,
  2767.                     NP_CloseOutput, FALSE,
  2768.                     TAG_DONE))
  2769.             {
  2770.                 smd->Message.mn_ReplyPort = NULL;
  2771.                 smd->Message.mn_Length = sizeof(struct SMData);
  2772.                 
  2773.                 smd->glob = glob;
  2774.                 smd->pref = pref;
  2775.                 
  2776.                 PutMsg(&proc->pr_MsgPort, (struct Message*)smd);
  2777.                 
  2778.                 Success = TRUE;
  2779.             }
  2780.             if (!Success) FreeVec(smd);
  2781.         }
  2782.         if (!Success) FreeAsync(glob, ScreenTask);
  2783.     } else Success = TRUE;
  2784.     
  2785.     if (!Success)
  2786.     {
  2787.         SyncSelectScreenMode(glob, pref);
  2788.     }
  2789. }
  2790.  
  2791.  
  2792.  
  2793. /*---------------------------------------------------*/
  2794. /* Asynchronously select an image and notify program */
  2795. /*---------------------------------------------------*/
  2796.  
  2797. struct SIData
  2798. {
  2799.     struct Message Message;
  2800.     struct Globals *glob;
  2801.     struct Prefs *pref;
  2802. };
  2803.  
  2804. void __saveds AsyncSelectImageTask(void)
  2805. {
  2806.     struct SIData *sid;
  2807.     struct Process *MyProc = (struct Process*)FindTask(NULL);
  2808.     struct Globals *glob;
  2809.     struct Prefs *pref;
  2810.     BOOL Success = FALSE;
  2811.     UBYTE *filename;
  2812.     UBYTE *ptr, save;
  2813.     BPTR dirlock;
  2814.     ULONG msglen;
  2815.     struct AppMessage *appm,*got;
  2816.     struct WBArg *argument;
  2817.     UBYTE *name;
  2818.     
  2819.     WaitPort(&MyProc->pr_MsgPort);
  2820.     if (sid = (struct SIData*)GetMsg(&MyProc->pr_MsgPort))
  2821.     {
  2822.         glob = sid->glob;
  2823.         pref = sid->pref;
  2824.         
  2825.         if (SelectImage(glob, &glob->ImageFR, pref->NewImage, sizeof(pref->NewImage)))
  2826.         {
  2827.             pref->Image = pref->NewImage;
  2828.             pref->Flags |= PREFF_BACKDROP;
  2829.             
  2830.             /* now fake an AppMessage to notify program of image change */
  2831.             
  2832.             filename = FilePart(pref->Image);
  2833.             
  2834.             ptr = PathPart(pref->Image);
  2835.             save = *ptr;
  2836.             *ptr = 0;
  2837.             
  2838.             if (dirlock = Lock(pref->Image, SHARED_LOCK))
  2839.             {
  2840.                 *ptr = save;
  2841.                 msglen = sizeof(struct AppMessage)+sizeof(struct WBArg)+strlen(filename)+1;
  2842.                 
  2843.                 if (appm = AllocVec(msglen,MEMF_ANY|MEMF_CLEAR))
  2844.                 {
  2845.                     argument = (struct WBArg*)(appm+1);
  2846.                     name = (UBYTE*)(argument+1);
  2847.                     
  2848.                     appm->am_Message.mn_Length = msglen;
  2849.                     appm->am_Message.mn_ReplyPort = &MyProc->pr_MsgPort;
  2850.                     
  2851.                     appm->am_Type = AMTYPE_APPWINDOW;
  2852.                     appm->am_NumArgs = 1;
  2853.                     appm->am_ArgList = argument;
  2854.                     
  2855.                     argument->wa_Lock = dirlock;
  2856.                     argument->wa_Name = name;
  2857.                     
  2858.                     strcpy(name, filename);
  2859.                     
  2860.                     PutMsg(&((struct Process*)MyTask)->pr_MsgPort, (struct Message*)appm);
  2861.                     
  2862.                     got = NULL;
  2863.                     while (got != appm)
  2864.                     {
  2865.                         WaitPort(&MyProc->pr_MsgPort);
  2866.                         got = (struct AppMessage*)GetMsg(&MyProc->pr_MsgPort);
  2867.                     }
  2868.                     FreeVec(appm);
  2869.                     
  2870.                     Success = TRUE;
  2871.                 }
  2872.                 UnLock(dirlock);
  2873.             }
  2874.             if (!Success) *ptr = save;
  2875.         }
  2876.         
  2877.         FreeVec(sid);
  2878.         
  2879.         Forbid();
  2880.         FreeAsync(glob, ImageTask);
  2881.     }
  2882. }
  2883.  
  2884. void AsyncSelectImage(struct Globals *glob, struct Prefs *pref)
  2885. {
  2886.     BOOL Success = FALSE;
  2887.     struct SIData *sid;
  2888.     struct Process *proc;
  2889.     
  2890.     if (AllocAsync(glob, ImageTask))
  2891.     {
  2892.         if (sid = AllocVec(sizeof(struct SIData), MEMF_ANY|MEMF_CLEAR))
  2893.         {
  2894.             if (proc = CreateNewProcTags(
  2895.                     NP_Entry, &AsyncSelectImageTask,
  2896.                     NP_Name, "Fireworks image selection task",
  2897.                     NP_Priority, 0,
  2898.                     NP_Input, Input(),
  2899.                     NP_Output, Output(),
  2900.                     NP_CloseInput, FALSE,
  2901.                     NP_CloseOutput, FALSE,
  2902.                     TAG_DONE))
  2903.             {
  2904.                 sid->Message.mn_ReplyPort = NULL;
  2905.                 sid->Message.mn_Length = sizeof(struct SIData);
  2906.                 
  2907.                 sid->glob = glob;
  2908.                 sid->pref = pref;
  2909.                 
  2910.                 PutMsg(&proc->pr_MsgPort, (struct Message*)sid);
  2911.                 
  2912.                 Success = TRUE;
  2913.             }
  2914.             if (!Success) FreeVec(sid);
  2915.         }
  2916.         if (!Success) FreeAsync(glob, ImageTask);
  2917.     } else Success = TRUE;
  2918.     
  2919.     if (!Success)
  2920.     {
  2921.         if (SelectImage(glob, &glob->ImageFR, pref->NewImage, sizeof(pref->NewImage)))
  2922.         {
  2923.             pref->Image = pref->NewImage;
  2924.             pref->Flags |= PREFF_BACKDROP;
  2925.             LoadImage(glob,pref);
  2926.         }
  2927.     }
  2928. }
  2929.  
  2930.  
  2931.  
  2932. /*------------------------------------------*/
  2933. /* Asynchronously select & play a MIDI file */
  2934. /*------------------------------------------*/
  2935.  
  2936. struct SPData
  2937. {
  2938.     struct Message Message;
  2939.     struct Globals *glob;
  2940.     struct Prefs *pref;
  2941. };
  2942.  
  2943. void SelectAndPlay(struct Globals *glob, struct Prefs *pref)
  2944. {
  2945.     if (SelectMIDI(glob, &glob->MIDIFR, pref->MIDIFile,sizeof(pref->MIDIFile)))
  2946.     {
  2947.         PlayMIDI(glob,pref);
  2948.     }
  2949. }
  2950.  
  2951. void __saveds AsyncSelectAndPlayTask(void)
  2952. {
  2953.     struct SPData *spd;
  2954.     struct Process *MyProc = (struct Process*)FindTask(NULL);
  2955.     struct Globals *glob;
  2956.     struct Prefs *pref;
  2957.     
  2958.     WaitPort(&MyProc->pr_MsgPort);
  2959.     if (spd = (struct SPData*)GetMsg(&MyProc->pr_MsgPort))
  2960.     {
  2961.         glob = spd->glob;
  2962.         pref = spd->pref;
  2963.         SelectAndPlay(glob,pref);
  2964.         
  2965.         FreeVec(spd);
  2966.         
  2967.         Forbid();
  2968.         FreeAsync(glob, PlayTask);
  2969.     }
  2970. }
  2971.  
  2972. void AsyncSelectAndPlay(struct Globals *glob, struct Prefs *pref)
  2973. {
  2974.     BOOL Success = FALSE;
  2975.     struct SPData *spd;
  2976.     struct Process *proc;
  2977.     
  2978.     if (AllocAsync(glob, PlayTask))
  2979.     {
  2980.         if (spd = AllocVec(sizeof(struct SPData), MEMF_ANY|MEMF_CLEAR))
  2981.         {
  2982.             if (proc = CreateNewProcTags(
  2983.                     NP_Entry, &AsyncSelectAndPlayTask,
  2984.                     NP_Name, "Fireworks MIDI selection task",
  2985.                     NP_Priority, 0,
  2986.                     NP_Input, Input(),
  2987.                     NP_Output, Output(),
  2988.                     NP_CloseInput, FALSE,
  2989.                     NP_CloseOutput, FALSE,
  2990.                     TAG_DONE))
  2991.             {
  2992.                 spd->Message.mn_ReplyPort = NULL;
  2993.                 spd->Message.mn_Length = sizeof(struct SPData);
  2994.                 
  2995.                 spd->glob = glob;
  2996.                 spd->pref = pref;
  2997.                 
  2998.                 PutMsg(&proc->pr_MsgPort, (struct Message*)spd);
  2999.                 
  3000.                 Success = TRUE;
  3001.             }
  3002.             if (!Success) FreeVec(spd);
  3003.         }
  3004.         if (!Success) FreeAsync(glob, PlayTask);
  3005.     } else Success = TRUE;
  3006.     
  3007.     if (!Success)
  3008.     {
  3009.         SelectAndPlay(glob, pref);
  3010.     }
  3011. }
  3012.  
  3013.  
  3014.  
  3015. /*----------------------------*/
  3016. /* Initialize/Update Graphics */
  3017. /*----------------------------*/
  3018.  
  3019. BOOL InitOrUpdateGraphics(struct Globals *glob, struct Prefs *pref)
  3020. {
  3021.     BOOL Success = FALSE;
  3022.     
  3023.     if (glob->PaintLayer)
  3024.     {
  3025.         DeleteLayer(0, glob->PaintLayer);
  3026.         glob->PaintLayer = NULL;
  3027.     }
  3028.     
  3029.     if (glob->BGBitMap)
  3030.     {
  3031.         FreeBitMap(glob->BGBitMap);
  3032.         glob->BGBitMap = NULL;
  3033.     }
  3034.     
  3035.     if (glob->PaintBitMap)
  3036.     {
  3037.         FreeBitMap(glob->PaintBitMap);
  3038.         glob->PaintBitMap = NULL;
  3039.     }
  3040.     
  3041.     if (glob->Window)
  3042.     {
  3043.         UWORD i;
  3044.         struct ColorMap *cmap = glob->Window->WScreen->ViewPort.ColorMap;
  3045.         
  3046.         struct BitMap *friend = glob->Window->RPort->BitMap;
  3047.         ULONG depth = GetBitMapAttr(friend, BMA_DEPTH);
  3048.         ULONG flags = GetBitMapAttr(friend, BMA_FLAGS);
  3049.         
  3050.         struct RastPort BGRP;
  3051.         
  3052.         SetPointer(glob->Window, WaitPointer, 16, 16, -6, 0);
  3053.         
  3054.         for (i = 0 ; i < NUMPENS ; i++)
  3055.         {
  3056.             if (glob->PenArray[i] == -1L)
  3057.             {
  3058.                 glob->PenArray[i] = ObtainBestPen(
  3059.                     cmap,
  3060.                     (ULONG)PenColors[i][0]<<24, 
  3061.                     (ULONG)PenColors[i][1]<<24, 
  3062.                     (ULONG)PenColors[i][2]<<24,
  3063.                     OBP_Precision, PRECISION_IMAGE,
  3064.                     TAG_DONE );
  3065.             }
  3066.         }
  3067.         
  3068.         /* Cybergraphics kludge */
  3069.         if ( !(flags & BMF_STANDARD) ) flags |= BMF_MINPLANES;
  3070.         
  3071.         if (glob->BGBitMap = AllocBitMap(glob->ww, glob->wh, depth, flags | BMF_CLEAR, friend))
  3072.         {
  3073.             struct BitMap *ImageBM   = NULL;
  3074.             struct BitMapHeader *bmh = NULL;
  3075.             
  3076.             InitRastPort(&BGRP);
  3077.             BGRP.BitMap = glob->BGBitMap;
  3078.             
  3079.             SetAPen(&BGRP, glob->PenArray[Backgroundpen]);
  3080.             
  3081.             if (glob->dto)
  3082.             {
  3083.                 GetDTAttrs(glob->dto, PDTA_DestBitMap, &ImageBM,
  3084.                                  PDTA_BitMapHeader, &bmh,
  3085.                             TAG_DONE);
  3086.             }
  3087.             
  3088.             if ((!ImageBM) || (!bmh))
  3089.             {
  3090.                 RectFill(&BGRP, 0, 0, (glob->ww)-1, (glob->wh)-1);
  3091.             }
  3092.             else
  3093.             {
  3094.                 UWORD width = bmh->bmh_Width;
  3095.                 UWORD height= bmh->bmh_Height;
  3096.                 
  3097.                 if (pref->Flags & PREFF_TILE)
  3098.                 {
  3099.                     UWORD x,y;
  3100.                     UWORD dow, doh;
  3101.                     
  3102.                     for (y = 0 ; y < glob->wh ; y += doh)
  3103.                     {
  3104.                         doh = height;
  3105.                         
  3106.                         if (y + doh > glob->wh)
  3107.                             doh = glob->wh - y;
  3108.                         
  3109.                         for (x = 0 ; x < glob->ww ; x += dow)
  3110.                         {
  3111.                             dow = width; 
  3112.                             
  3113.                             if (x + dow > glob->ww)
  3114.                                 dow = glob->ww - x;
  3115.                             
  3116.                             BltBitMap(ImageBM, 0, 0, glob->BGBitMap, x, y, dow, doh, 0xc0, 0xff,NULL);
  3117.                         }
  3118.                     }
  3119.                 }
  3120.                 else
  3121.                 {
  3122.                     struct BitScaleArgs bsa;
  3123.                     
  3124.                     bsa.bsa_SrcX        = 0;
  3125.                     bsa.bsa_SrcY        = 0;
  3126.                     bsa.bsa_SrcWidth    = width;
  3127.                     bsa.bsa_SrcHeight    = height;
  3128.                     bsa.bsa_XSrcFactor    = width;
  3129.                     bsa.bsa_YSrcFactor    = height;
  3130.                     bsa.bsa_DestX        = 0;
  3131.                     bsa.bsa_DestY        = 0;
  3132.                     bsa.bsa_DestWidth    = glob->ww;
  3133.                     bsa.bsa_DestHeight    = glob->wh;
  3134.                     bsa.bsa_XDestFactor    = glob->ww;
  3135.                     bsa.bsa_YDestFactor    = glob->wh;
  3136.                     bsa.bsa_SrcBitMap    = ImageBM;
  3137.                     bsa.bsa_DestBitMap    = glob->BGBitMap;
  3138.                     bsa.bsa_Flags        = 0;
  3139.                     bsa.bsa_XDDA        = 0;
  3140.                     bsa.bsa_YDDA        = 0;
  3141.                     bsa.bsa_Reserved1    = 0;
  3142.                     bsa.bsa_Reserved2    = 0;
  3143.                     
  3144.                     BitMapScale(&bsa);
  3145.                 }
  3146.             }
  3147.             
  3148.             if ( glob->PaintBitMap = AllocBitMap(glob->ww, glob->wh, depth, flags | BMF_CLEAR, friend))
  3149.             {
  3150.                 InitRastPort(&glob->PaintRP);
  3151.                 glob->PaintRP.BitMap = glob->PaintBitMap;
  3152.                 
  3153.                 if (!(glob->LInfo)) glob->LInfo = NewLayerInfo();
  3154.                 
  3155.                 if (glob->LInfo)
  3156.                 {
  3157.                     if (glob->PaintLayer = CreateUpfrontLayer(glob->LInfo, glob->PaintBitMap, 0, 0, (glob->ww)-1, (glob->wh)-1, LAYERSMART, NULL))
  3158.                     {
  3159.                         glob->PaintRP.Layer = glob->PaintLayer;
  3160.                         
  3161.                         BltBitMapRastPort(glob->BGBitMap, 0, 0, &glob->PaintRP, 0, 0, glob->ww, glob->wh, 0xc0);
  3162.                         
  3163.                         Success = TRUE;
  3164.                     }
  3165.                 }
  3166.             }
  3167.         }
  3168.         ClearPointer(glob->Window);
  3169.     }
  3170.     
  3171.     if (!Success)
  3172.     {
  3173.         if (glob->PaintLayer)
  3174.         {
  3175.             DeleteLayer(0, glob->PaintLayer);
  3176.             glob->PaintLayer = NULL;
  3177.         }
  3178.         
  3179.         if (glob->BGBitMap)
  3180.         {
  3181.             FreeBitMap(glob->BGBitMap);
  3182.             glob->BGBitMap = NULL;
  3183.         }
  3184.         
  3185.         if (glob->PaintBitMap)
  3186.         {
  3187.             FreeBitMap(glob->PaintBitMap);
  3188.             glob->PaintBitMap = NULL;
  3189.         }
  3190.     }
  3191.     
  3192.     return(Success);
  3193. }
  3194.  
  3195.  
  3196.  
  3197. /*-------------------------*/
  3198. /* Free allocated Graphics */
  3199. /*-------------------------*/
  3200.  
  3201. void FreeGraphics(struct Globals *glob)
  3202. {
  3203.     UWORD i;
  3204.     
  3205.     if (glob->dto)
  3206.     {
  3207.         SetAPen(glob->Window->RPort, glob->PenArray[Backgroundpen]);
  3208.         RectFill(glob->Window->RPort, 0, 0, (glob->ww)-1, (glob->wh)-1);
  3209.         
  3210.         DisposeDTObject(glob->dto);
  3211.         glob->dto = NULL;
  3212.     }
  3213.     
  3214.     if (glob->PaintLayer)
  3215.     {
  3216.         DeleteLayer(0, glob->PaintLayer);
  3217.         glob->PaintLayer = NULL;
  3218.     }
  3219.     
  3220.     if (glob->LInfo)
  3221.     {
  3222.         DisposeLayerInfo(glob->LInfo);
  3223.         glob->LInfo = NULL;
  3224.     }
  3225.     
  3226.     if (glob->BGBitMap)
  3227.     {
  3228.         FreeBitMap(glob->BGBitMap);
  3229.         glob->BGBitMap = NULL;
  3230.     }
  3231.     
  3232.     if (glob->PaintBitMap)
  3233.     {
  3234.         FreeBitMap(glob->PaintBitMap);
  3235.         glob->PaintBitMap = NULL;
  3236.     }
  3237.     
  3238.     if (glob->Window)
  3239.     {
  3240.         struct ColorMap *cmap = glob->Window->WScreen->ViewPort.ColorMap;
  3241.         
  3242.         for (i = 0 ; i < NUMPENS ; i++)
  3243.         {
  3244.             if (glob->PenArray[i] != -1L)
  3245.             {
  3246.                 ReleasePen( cmap, glob->PenArray[i] );
  3247.                 glob->PenArray[i] = -1L;
  3248.             }
  3249.         }
  3250.     }
  3251. }
  3252.  
  3253.  
  3254.  
  3255. /*--------------------*/
  3256. /* Get current screen */
  3257. /*--------------------*/
  3258.  
  3259. struct Screen *GetScreen(struct Globals *glob)
  3260. {
  3261.     struct Window *win;
  3262.     struct Screen *scr = NULL;
  3263.     
  3264.     if (MyTask)
  3265.     {
  3266.         win = ((struct Window*)((struct Process*)MyTask)->pr_WindowPtr);
  3267.         if (win) scr = win->WScreen;
  3268.     }
  3269.     
  3270.     if (!scr)
  3271.     {
  3272.         if (glob->LockedScreen)
  3273.             scr = glob->LockedScreen;
  3274.         else
  3275.             scr = glob->LockedScreen = LockPubScreen(NULL);
  3276.     }
  3277.     
  3278.     return(scr);
  3279. }
  3280.  
  3281.  
  3282.  
  3283.  
  3284. /*----------------------------------*/
  3285. /* Load image using datatypes (V43) */
  3286. /*----------------------------------*/
  3287.  
  3288. void LoadImage(struct Globals *glob, struct Prefs *pref)
  3289. {
  3290.     if (glob->dto)
  3291.     {
  3292.         SetAPen(glob->Window->RPort, glob->PenArray[Backgroundpen]);
  3293.         RectFill(glob->Window->RPort, 0, 0, (glob->ww)-1, (glob->wh)-1);
  3294.         
  3295.         DisposeDTObject(glob->dto);
  3296.         glob->dto = NULL;
  3297.     }
  3298.     
  3299.     SetPointer(glob->Window, WaitPointer, 16, 16, -6, 0);
  3300.     
  3301.     if (glob->dto = (Object *) NewDTObject(pref->Image,
  3302.         DTA_GroupID, GID_PICTURE, 
  3303.         PDTA_DestMode, MODE_V43,
  3304.         PDTA_Remap, TRUE,
  3305.         PDTA_Screen, GetScreen(glob),
  3306.         PDTA_FreeSourceBitMap, TRUE,
  3307.         TAG_DONE) )
  3308.     {
  3309.         SetDTAttrs(glob->dto, NULL, NULL,
  3310.                     PDTA_Remap, TRUE,
  3311.                     PDTA_Screen, GetScreen(glob),
  3312.                     PDTA_FreeSourceBitMap, TRUE,
  3313.                     PDTA_UseFriendBitMap, TRUE,
  3314.                     TAG_DONE );
  3315.         
  3316.         DoMethod( glob->dto, DTM_PROCLAYOUT, NULL, TRUE );
  3317.     }
  3318.     else
  3319.     {
  3320.         LONG errnum=IoErr();
  3321.         UBYTE errstring[80];
  3322.         
  3323.         if (errnum>=DTERROR_UNKNOWN_DATATYPE)
  3324.         {
  3325.             SPrintf(errstring,GetDTString(errnum),pref->Image);
  3326.         }
  3327.         else
  3328.         {
  3329.             Fault(errnum,NULL,errstring,sizeof(errstring));
  3330.         }
  3331.         Message("%s: %s",NULL,pref->Image,errstring);
  3332.     }
  3333.     
  3334.     if (!(InitOrUpdateGraphics(glob,pref)))
  3335.     {
  3336.         Message("Failed to update graphics!",NULL);
  3337.     }
  3338.     
  3339.     if (glob->PaintBitMap)
  3340.     {
  3341.         BltBitMapRastPort(glob->PaintBitMap, 0, 0, glob->Window->RPort, 0, 0, glob->ww, glob->wh, 0xc0);
  3342.     }
  3343.     else EraseRect(glob->Window->RPort, 0, 0, (glob->ww)-1, (glob->wh)-1);
  3344.     
  3345.     ClearPointer(glob->Window);
  3346. }
  3347.  
  3348.  
  3349.  
  3350. /*-------------------------------------------*/
  3351. /* Datatypes hook function for ASL requester */
  3352. /*-------------------------------------------*/
  3353.  
  3354. ULONG __asm __saveds Filter (register __a0 struct Hook *h, register __a2 struct FileRequester *fr, register __a1 struct AnchorPath *ap)
  3355. {
  3356.     struct DataType *dtn;
  3357.     ULONG use = FALSE;
  3358.     UBYTE buffer[300];
  3359.     BPTR lock;
  3360.     
  3361.     if (ap->ap_Info.fib_DirEntryType > 0)
  3362.     {
  3363.         use = TRUE;
  3364.     }
  3365.     else
  3366.     {
  3367.         strncpy (buffer, fr->fr_Drawer, sizeof (buffer));
  3368.         AddPart (buffer, ap->ap_Info.fib_FileName, sizeof (buffer));
  3369.         if (lock = Lock (buffer, ACCESS_READ))
  3370.         {
  3371.             if (dtn = ObtainDataTypeA (DTST_FILE, (APTR) lock, NULL))
  3372.             {
  3373.                 if (dtn->dtn_Header->dth_GroupID == GID_PICTURE)
  3374.                     use = TRUE;
  3375.                 
  3376.                 ReleaseDataType (dtn);
  3377.             }
  3378.             UnLock (lock);
  3379.         }
  3380.     }
  3381.     return (use);
  3382. }
  3383.  
  3384.  
  3385.  
  3386. /*--------------------------------------*/
  3387. /* Select image to load (ASL requester) */
  3388. /*--------------------------------------*/
  3389.  
  3390. BOOL SelectImage(struct Globals *glob, struct FileRequester **fr, UBYTE *filebuffer, ULONG MaxSize)
  3391. {
  3392.     BOOL Selected=FALSE;
  3393.     
  3394.     UBYTE initialdrawer[200];
  3395.     UBYTE initialfile  [40];
  3396.     
  3397.     struct Hook filter = {NULL, NULL, NULL, NULL, NULL};
  3398.     UBYTE save, *ptr;
  3399.     
  3400.     filter.h_Entry = (HOOKFUNC)Filter;
  3401.     
  3402.     ptr = PathPart(filebuffer);
  3403.     save = *ptr; *ptr = 0;
  3404.     strncpy (initialdrawer,filebuffer,sizeof(initialdrawer));
  3405.     initialdrawer[sizeof(initialdrawer)-1]=0;
  3406.     *ptr = save;
  3407.     strncpy (initialfile, FilePart(filebuffer), sizeof(initialfile));
  3408.     initialfile[sizeof(initialfile)-1]=0;
  3409.     
  3410.     if (!(*fr))
  3411.     {
  3412.         if(!((*fr) = AllocAslRequestTags (ASL_FileRequest,
  3413.                     ASLFR_TitleText,    "Select Picture to load",
  3414.                     ASLFR_PositiveText,    "Load",
  3415.                     ASLFR_RejectIcons,    TRUE,
  3416.                     ASLFR_DoPatterns, TRUE,
  3417.                     TAG_DONE)))
  3418.         {
  3419.             Message("Couldn't allocate asl requester",NULL);
  3420.         }
  3421.     }
  3422.     
  3423.     if (*fr)
  3424.     {
  3425.         Selected = AslRequestTags(*fr,
  3426.             ASLFR_Screen, GetScreen(glob),
  3427.             ASLFR_InitialDrawer, initialdrawer,
  3428.             ASLFR_InitialFile, initialfile,
  3429.             ASLFR_FilterFunc,    &filter,
  3430.             TAG_DONE);
  3431.         
  3432.         if (Selected)
  3433.         {
  3434.             strncpy (filebuffer, (*fr)->fr_Drawer, MaxSize);
  3435.             AddPart (filebuffer, (*fr)->fr_File,   MaxSize);
  3436.         }
  3437.     }
  3438.     
  3439.     return(Selected);
  3440. }
  3441.  
  3442.  
  3443.  
  3444. /*--------------------------------------*/
  3445. /* MIDI hook function for ASL requester */
  3446. /*--------------------------------------*/
  3447.  
  3448. ULONG __asm __saveds MIDIFilter (register __a0 struct Hook *h, register __a2 struct FileRequester *fr, register __a1 struct AnchorPath *ap)
  3449. {
  3450.     ULONG use = FALSE;
  3451.     
  3452.     UBYTE buffer[300];
  3453.     UBYTE header[20];
  3454.     BPTR file;
  3455.     int l = 0;
  3456.     
  3457.     if (ap->ap_Info.fib_DirEntryType >0)
  3458.         use = TRUE;
  3459.     else
  3460.     {
  3461.         strncpy (buffer, fr->fr_Drawer, sizeof (buffer));
  3462.         AddPart (buffer, ap->ap_Info.fib_FileName, sizeof (buffer));
  3463.         
  3464.         if (file = Open (buffer, MODE_OLDFILE))
  3465.         {
  3466.             l=Read(file,header,sizeof(header));
  3467.             Close (file);
  3468.         }
  3469.         
  3470.         if (l==sizeof(header))
  3471.         {
  3472.             if ( ((header[0] == 'M') &&
  3473.                   (header[1] == 'T') &&
  3474.                   (header[2] == 'h') &&
  3475.                   (header[3] == 'd'))
  3476.                 
  3477.                 ||
  3478.                 
  3479.                  ((header[0] == 'X') &&
  3480.                   (header[1] == 'P') &&
  3481.                   (header[2] == 'K') &&
  3482.                   (header[3] == 'F') &&
  3483.                   (header[16]== 'M') &&
  3484.                   (header[17]== 'T') &&
  3485.                   (header[18]== 'h') &&
  3486.                   (header[19]== 'd')) )
  3487.             {
  3488.                 use = TRUE;
  3489.             }
  3490.         }
  3491.     }
  3492.     return(use);
  3493. }
  3494.  
  3495.  
  3496.  
  3497. /*----------------------------*/
  3498. /* Select a MIDI file to load */
  3499. /*----------------------------*/
  3500.  
  3501. BOOL SelectMIDI(struct Globals *glob, struct FileRequester **fr, UBYTE *filebuffer, ULONG MaxSize)
  3502. {
  3503.     BOOL Selected=FALSE;
  3504.     
  3505.     UBYTE initialdrawer[200];
  3506.     UBYTE initialfile  [40];
  3507.     
  3508.     struct Hook filter = {NULL, NULL, NULL, NULL, NULL};
  3509.     UBYTE save, *ptr;
  3510.     
  3511.     filter.h_Entry = (HOOKFUNC)MIDIFilter;
  3512.     
  3513.     ptr = PathPart(filebuffer);
  3514.     save = *ptr; *ptr = 0;
  3515.     strncpy (initialdrawer,filebuffer,sizeof(initialdrawer));
  3516.     initialdrawer[sizeof(initialdrawer)-1]=0;
  3517.     *ptr = save;
  3518.     strncpy (initialfile, FilePart(filebuffer), sizeof(initialfile));
  3519.     initialfile[sizeof(initialfile)-1]=0;
  3520.     
  3521.     if (!(*fr))
  3522.     {
  3523.         if (!((*fr) = AllocAslRequestTags (ASL_FileRequest,
  3524.                     ASLFR_TitleText,    "Select MIDI file to play",
  3525.                     ASLFR_PositiveText,    "Play",
  3526.                     ASLFR_RejectIcons,    TRUE,
  3527.                     ASLFR_DoPatterns, TRUE,
  3528.                     TAG_DONE)))
  3529.         {
  3530.             Message("Couldn't allocate asl requester",NULL);
  3531.         }
  3532.     }
  3533.     
  3534.     if (*fr)
  3535.     {
  3536.         Selected = AslRequestTags(*fr,
  3537.                     ASLFR_Screen, GetScreen(glob),
  3538.                     ASLFR_FilterFunc,    &filter,
  3539.                     ASLFR_InitialDrawer, initialdrawer,
  3540.                     ASLFR_InitialFile, initialfile,
  3541.                     TAG_DONE);
  3542.         
  3543.         if (Selected)
  3544.         {
  3545.             strncpy (filebuffer, (*fr)->fr_Drawer, MaxSize);
  3546.             AddPart (filebuffer, (*fr)->fr_File,   MaxSize);
  3547.         }
  3548.     }
  3549.     
  3550.     return(Selected);
  3551. }
  3552.  
  3553.  
  3554. /*-----------------------------------*/
  3555. /* Invoke PlayMF to play a MIDI file */
  3556. /*-----------------------------------*/
  3557.  
  3558. void PlayMIDI(struct Globals *glob, struct Prefs *pref)
  3559. {
  3560.     UBYTE CommandString[300];
  3561.     BPTR lock;
  3562.     BPTR out;
  3563.     BOOL CloseOut = FALSE;
  3564.     
  3565.     if (lock = Lock("/PlayMF/PlayMF", SHARED_LOCK ))
  3566.     {
  3567.         UnLock(lock);
  3568.         
  3569.         SPrintf(CommandString,"Run >NIL: /PlayMF/PlayMF \42%s\42 LINK=\42%s\42 REPLACE", pref->MIDIFile, pref->Link);
  3570.     }
  3571.     else
  3572.     {
  3573.         SPrintf(CommandString,"Run >NIL: PlayMF \42%s\42 LINK=\42%s\42 REPLACE", pref->MIDIFile, pref->Link);
  3574.     }
  3575.     
  3576.     if ((out = Output()) == NULL)
  3577.     {
  3578.         if (out = Open("NIL:", MODE_OLDFILE)) CloseOut = TRUE;
  3579.     }
  3580.     
  3581.     if (!Execute( CommandString, NULL, out))
  3582.     {
  3583.         AsyncMessage(glob,LaunchTask, "Unable to launch PlayMF.\nPlease make sure it is located somewhere in your search path.","Damn");
  3584.     }
  3585.     
  3586.     if (CloseOut) Close(out);
  3587. }
  3588.  
  3589.  
  3590. /*--------------------------*/
  3591. /* Stop PlayMF (if running) */
  3592. /*--------------------------*/
  3593.  
  3594. void StopMIDI(struct Globals *glob, struct Prefs *pref)
  3595. {
  3596.     APTR lock;
  3597.     struct MidiCluster *clust;
  3598.     struct MidiLink *ml;
  3599.     
  3600.     if (lock = LockCAMD(CD_Linkages))
  3601.     {
  3602.         if (clust = FindCluster(pref->Link))
  3603.         {
  3604.             for (ml = (struct MidiLink*)clust->mcl_Senders.lh_Head ;
  3605.                  ml->ml_Node.ln_Succ ;
  3606.                  ml = (struct MidiLink*)ml->ml_Node.ln_Succ )
  3607.             {
  3608.                 if (!stricmp("PlayMF Player", ml->ml_MidiNode->mi_Node.ln_Name))
  3609.                 {
  3610.                     Signal(ml->ml_MidiNode->mi_SigTask, SIGBREAKF_CTRL_C);
  3611.                     break;
  3612.                 }
  3613.             }
  3614.         }
  3615.         UnlockCAMD(lock);
  3616.     }
  3617. }
  3618.  
  3619.  
  3620. /*----------------*/
  3621. /* Open Libraries */
  3622. /*----------------*/
  3623.  
  3624. BOOL OpenLibs(void)
  3625. {
  3626.     BOOL Success=FALSE;
  3627.     
  3628.     SysBase = *((struct ExecBase**)(0x4));
  3629.     
  3630.     if (DOSBase=(struct DosLibrary*)OpenLibrary("dos.library",39L))
  3631.     {
  3632.         if (GfxBase=(struct GfxBase*)OpenLibrary("graphics.library",39L))
  3633.         {
  3634.             if (LayersBase=OpenLibrary("layers.library",39L))
  3635.             {
  3636.                 if (IntuitionBase=(struct IntuitionBase*)OpenLibrary("intuition.library",39L))
  3637.                 {
  3638.                     if (GadToolsBase=OpenLibrary("gadtools.library", 39L))
  3639.                     {
  3640.                         if (UtilityBase=OpenLibrary("utility.library",39L))
  3641.                         {
  3642.                             if (!(DatatypesBase=OpenLibrary("datatypes.library",39L)))
  3643.                             {
  3644.                                 Message("This program requires datatypes.library!",NULL);
  3645.                             }
  3646.                             else
  3647.                             {
  3648.                                 if (!(AslBase=OpenLibrary("asl.library",39L)))
  3649.                                 {
  3650.                                     Message("This program requires asl.library!",NULL);
  3651.                                 }
  3652.                                 else
  3653.                                 {
  3654.                                     if (!(WorkbenchBase=OpenLibrary("workbench.library",39L)))
  3655.                                     {
  3656.                                         Message("This program requires workbench.library!",NULL);
  3657.                                     }
  3658.                                     else
  3659.                                     {
  3660.                                         if (!(CamdBase=OpenLibrary("camd.library",0L)))
  3661.                                         {
  3662.                                             Message("This program requires camd.library!",NULL);
  3663.                                         }
  3664.                                         else
  3665.                                         {
  3666.                                             if ( __fpinit() )
  3667.                                             {
  3668.                                                 Message("Unable to initialize floating point!",NULL);
  3669.                                             }
  3670.                                             else
  3671.                                             {
  3672.                                                 FPBase=TRUE;
  3673.                                                 
  3674.                                                 Success=TRUE;
  3675.                                             }
  3676.                                         }
  3677.                                     }
  3678.                                 }
  3679.                             }
  3680.                         }
  3681.                     }
  3682.                 }
  3683.             }
  3684.         }
  3685.     }
  3686.     if (!Success) CloseLibs();
  3687.     
  3688.     return(Success);
  3689. }
  3690.  
  3691.  
  3692. /*-----------------*/
  3693. /* Close Libraries */
  3694. /*-----------------*/
  3695.  
  3696. void CloseLibs(void)
  3697. {
  3698.     if (FPBase)
  3699.     {
  3700.         __fpterm();
  3701.         FPBase=FALSE;
  3702.     }
  3703.     
  3704.     if (CamdBase)
  3705.     {
  3706.         CloseLibrary(CamdBase);
  3707.         CamdBase=NULL;
  3708.     }
  3709.     
  3710.     if (WorkbenchBase)
  3711.     {
  3712.         CloseLibrary(WorkbenchBase);
  3713.         WorkbenchBase=NULL;
  3714.     }
  3715.     
  3716.     if (AslBase)
  3717.     {
  3718.         CloseLibrary(AslBase);
  3719.         AslBase=NULL;
  3720.     }
  3721.     
  3722.     if (DatatypesBase)
  3723.     {
  3724.         CloseLibrary(DatatypesBase);
  3725.         DatatypesBase=NULL;
  3726.     }
  3727.     
  3728.     if (UtilityBase)
  3729.     {
  3730.         CloseLibrary(UtilityBase);
  3731.         UtilityBase=NULL;
  3732.     }
  3733.     
  3734.     if (GadToolsBase)
  3735.     {
  3736.         CloseLibrary(GadToolsBase);
  3737.         GadToolsBase=NULL;
  3738.     }
  3739.     
  3740.     if (IntuitionBase)
  3741.     {
  3742.         CloseLibrary((struct Library*)IntuitionBase);
  3743.         IntuitionBase=NULL;
  3744.     }
  3745.     
  3746.     if (LayersBase)
  3747.     {
  3748.         CloseLibrary((struct Library*)LayersBase);
  3749.         LayersBase=NULL;
  3750.     }
  3751.     
  3752.     if (GfxBase)
  3753.     {
  3754.         CloseLibrary((struct Library*)GfxBase);
  3755.         GfxBase=NULL;
  3756.     }
  3757.     
  3758.     if (DOSBase)
  3759.     {
  3760.         CloseLibrary((struct Library*)DOSBase);
  3761.         DOSBase=NULL;
  3762.     }
  3763. }
  3764.  
  3765.  
  3766. /*-------------------*/
  3767. /* Open timer device */
  3768. /*-------------------*/
  3769.  
  3770. struct timerequest *OpenTimer(void)
  3771. {
  3772.     BOOL Success = FALSE;
  3773.     
  3774.     struct MsgPort *reply = NULL;
  3775.     struct timerequest *treq = NULL;
  3776.     
  3777.     if (!(reply = CreateMsgPort()))
  3778.     {
  3779.         Message("Unable to create timer port!",NULL);
  3780.     }
  3781.     else
  3782.     {
  3783.         if (!(treq = CreateIORequest(reply, sizeof(struct timerequest))))
  3784.         {
  3785.             Message("Unable to create timer request!",NULL);
  3786.         }
  3787.         else
  3788.         {
  3789.             if (OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest*)treq,0))
  3790.             {
  3791.                 Message("Timer: Cannot open timer.device (UNIT_VBLANK).",NULL);
  3792.             }
  3793.             else
  3794.             {
  3795.                 TimerBase = (struct Library*)treq->tr_node.io_Device;
  3796.                 Success = TRUE;
  3797.             }
  3798.         }
  3799.     }
  3800.     
  3801.     if (!Success)
  3802.     {
  3803.         if (TimerBase)
  3804.         {
  3805.             CloseDevice((struct IORequest*)treq);
  3806.             TimerBase = NULL;
  3807.         }
  3808.         
  3809.         if (treq)
  3810.         {
  3811.             DeleteIORequest(treq);
  3812.             treq = NULL;
  3813.         }
  3814.         
  3815.         if (reply)
  3816.         {
  3817.             DeleteMsgPort(reply);
  3818.             reply = NULL;
  3819.         }
  3820.     }
  3821.     
  3822.     return(treq);
  3823. }
  3824.  
  3825.  
  3826.  
  3827. /*--------------------*/
  3828. /* Close timer device */
  3829. /*--------------------*/
  3830.  
  3831. void CloseTimer(struct timerequest *treq)
  3832. {
  3833.     struct MsgPort *reply = NULL;
  3834.     
  3835.     if (treq)
  3836.     {
  3837.         if (treq->tr_node.io_Device)
  3838.         {
  3839.             CloseDevice((struct IORequest*)treq);
  3840.             TimerBase = NULL;
  3841.         }
  3842.         
  3843.         reply = treq->tr_node.io_Message.mn_ReplyPort;
  3844.         
  3845.         DeleteIORequest(treq);
  3846.         treq = NULL;
  3847.     }
  3848.     
  3849.     if (reply)
  3850.     {
  3851.         DeleteMsgPort(reply);
  3852.         reply = NULL;
  3853.     }
  3854. }
  3855.  
  3856.  
  3857. /*----------------*/
  3858. /* Get Time Delta */
  3859. /*----------------*/
  3860.  
  3861. /* This function returns the time difference in milliseconds */
  3862. /* to the time it was called last                            */
  3863.  
  3864. struct EClockVal eclock;
  3865.  
  3866. ULONG GetTimeDelta(void)
  3867. {
  3868.     // ULONG old_hi = eclock.ev_hi;
  3869.     ULONG old_lo = eclock.ev_lo;
  3870.     ULONG E_Freq = ReadEClock(&eclock);
  3871.     
  3872.     ULONG delta = 1000 * (eclock.ev_lo - old_lo) / E_Freq;
  3873.     
  3874.     return(delta);
  3875. }
  3876.  
  3877.  
  3878.  
  3879. /*****************************************************************************/
  3880.  
  3881. /*------------------------------------------*/
  3882. /* Keep track of the number of Asynch tasks */
  3883. /*------------------------------------------*/
  3884.  
  3885. BOOL AllocAsync(struct Globals *glob, TaskFlag flg)
  3886. {
  3887.     BOOL success = FALSE;
  3888.     
  3889.     Forbid();
  3890.     if (!(glob->TaskAlloc & flg))
  3891.     {
  3892.         glob->TaskAlloc |= flg;
  3893.         success = TRUE;
  3894.     }
  3895.     Permit();
  3896.     
  3897.     if (!success) if (IntuitionBase) DisplayBeep(NULL);
  3898.     
  3899.     return(success);
  3900. }
  3901.  
  3902. void FreeAsync(struct Globals *glob, TaskFlag flg)
  3903. {
  3904.     Forbid();
  3905.     if (glob->TaskAlloc & flg)
  3906.     {
  3907.         glob->TaskAlloc &= (~flg);
  3908.     }
  3909.     Permit();
  3910.     
  3911.     if (!glob->TaskAlloc) Signal(MyTask, SIGBREAKF_CTRL_F);
  3912. }
  3913.  
  3914. BOOL AskAsync(struct Globals *glob)
  3915. {
  3916.     BOOL result = FALSE;
  3917.     
  3918.     if (!glob->TaskAlloc) result = TRUE;
  3919.     
  3920.     return(result);
  3921. }
  3922.  
  3923. void WaitAsync(struct Globals *glob)
  3924. {
  3925.     while (glob->TaskAlloc)
  3926.     {
  3927.         Wait(SIGBREAKF_CTRL_F);
  3928.     }
  3929. }
  3930.  
  3931.  
  3932.  
  3933. /*----------------------------*/
  3934. /* Show a message to the user */
  3935. /*----------------------------*/
  3936.  
  3937. LONG __stdargs Message(UBYTE *Msg,UBYTE *Options,...)
  3938. {
  3939.     LONG retval;
  3940.     
  3941.     va_list Args;
  3942.     va_start(Args,Options);
  3943.     
  3944.     retval = MessageA(Msg, Options, Args);
  3945.     
  3946.     va_end(Args);
  3947.     
  3948.     return(retval);
  3949. }
  3950.  
  3951. LONG MessageA(UBYTE *Msg,UBYTE *Options,APTR Args)
  3952. {
  3953.     LONG retval;
  3954.     
  3955.     BOOL req = FALSE;
  3956.     
  3957.     
  3958.     // if (Options) if (strchr(Options,'|')) req = TRUE;
  3959.     if (Options) req = TRUE;
  3960.     
  3961.     if (IntuitionBase && (WBMode || req))
  3962.     {
  3963.         struct EasyStruct Req={sizeof(struct EasyStruct),0,"Fireworks",0, NULL};
  3964.         
  3965.         if (!Options) Options = "I see";
  3966.         
  3967.         Req.es_TextFormat=Msg;
  3968.         Req.es_GadgetFormat=Options;
  3969.         
  3970.         retval=EasyRequestArgs(((struct Process*)MyTask)->pr_WindowPtr,&Req,0,Args);
  3971.     }
  3972.     else
  3973.     {
  3974.         if (DOSBase)
  3975.         {
  3976.             VPrintf(Msg,Args);
  3977.             Printf("\n");
  3978.             
  3979.             retval=0;
  3980.         }
  3981.     }
  3982.     return(retval);
  3983. }
  3984.  
  3985.  
  3986. /*------------------------------------------*/
  3987. /* Show non-blocking (asynchronous) message */
  3988. /*------------------------------------------*/
  3989.  
  3990. struct MsgData
  3991. {
  3992.     struct Message Message;
  3993.     struct Globals *glob;
  3994.     TaskFlag flg;
  3995.     UBYTE *Msg;
  3996.     UBYTE *Options;
  3997.     APTR Args;
  3998. };
  3999.  
  4000. void __saveds AsyncMessageTask(void)
  4001. {
  4002.     struct MsgData *md;
  4003.     struct Process *MyProc = (struct Process*)FindTask(NULL);
  4004.     struct Globals *glob;
  4005.     TaskFlag flg;
  4006.     
  4007.     WaitPort(&MyProc->pr_MsgPort);
  4008.     if (md = (struct MsgData*)GetMsg(&MyProc->pr_MsgPort))
  4009.     {
  4010.         glob = md->glob;
  4011.         flg  = md->flg;
  4012.         
  4013.         MessageA(md->Msg, md->Options, md->Args);
  4014.         
  4015.         FreeVec(md);
  4016.         
  4017.         Forbid();
  4018.         FreeAsync(glob, flg);
  4019.     }
  4020. }
  4021.  
  4022. LONG __stdargs AsyncMessage(struct Globals *glob, TaskFlag flg, UBYTE *Msg,UBYTE *Options,...)
  4023. {
  4024.     BOOL Success = FALSE;
  4025.     BOOL req = FALSE;
  4026.     struct Process *proc;
  4027.     struct MsgData *md;
  4028.     
  4029.     va_list Args;
  4030.     va_start(Args,Options);
  4031.     
  4032.     // if (Options) if (strchr(Options,'|')) req = TRUE;
  4033.     if (Options) req = TRUE;
  4034.     
  4035.     if (IntuitionBase && (WBMode || req))
  4036.     {
  4037.         if (AllocAsync(glob, flg))
  4038.         {
  4039.             if (md = AllocVec(sizeof(struct MsgData), MEMF_ANY|MEMF_CLEAR))
  4040.             {
  4041.                 if (proc = CreateNewProcTags(
  4042.                         NP_Entry, &AsyncMessageTask,
  4043.                         NP_Name, "Fireworks messaging task",
  4044.                         NP_Priority, 0,
  4045.                         NP_Input, Input(),
  4046.                         NP_Output, Output(),
  4047.                         NP_CloseInput, FALSE,
  4048.                         NP_CloseOutput, FALSE,
  4049.                         TAG_DONE))
  4050.                 {
  4051.                     md->Message.mn_ReplyPort = NULL;
  4052.                     md->Message.mn_Length = sizeof(struct MsgData);
  4053.                     
  4054.                     md->glob = glob;
  4055.                     md->flg = flg;
  4056.                     md->Msg = Msg;
  4057.                     md->Options= Options;
  4058.                     md->Args = Args;
  4059.                     
  4060.                     PutMsg(&proc->pr_MsgPort, (struct Message*)md);
  4061.                     
  4062.                     Success = TRUE;
  4063.                 }
  4064.                 if (!Success) FreeVec(md);
  4065.             }
  4066.             if (!Success) FreeAsync(glob, flg);
  4067.         } else Success = TRUE;
  4068.     }
  4069.     
  4070.     if (!Success)
  4071.     {
  4072.         MessageA(Msg,Options,Args);
  4073.     }
  4074.     
  4075.     va_end(Args);
  4076.     
  4077.     return(0);
  4078. }
  4079.  
  4080.  
  4081. /*-----------------------*/
  4082. /* Standard Exit routine */
  4083. /*-----------------------*/
  4084.  
  4085. void __stdargs _XCEXIT(LONG lcode)
  4086. {
  4087.     Message("Task wants to exit, return code %ld\nHolding task!", NULL, lcode);
  4088.     Wait(0);
  4089. }
  4090.  
  4091.  
  4092. /*-------------------*/
  4093. /* CAM Library stubs */
  4094. /*-------------------*/
  4095.  
  4096. struct MidiNode *CreateMidi(Tag tag, ...)
  4097. {
  4098.     return CreateMidiA((struct TagItem *)&tag );
  4099. }
  4100.  
  4101. BOOL SetMidiAttrs(struct MidiNode *mi, Tag tag, ...)
  4102. {
  4103.     return SetMidiAttrsA(mi, (struct TagItem *)&tag );
  4104. }
  4105.  
  4106. struct MidiLink *AddMidiLink(struct MidiNode *mi, LONG type, Tag tag, ...)
  4107. {
  4108.     return AddMidiLinkA(mi, type, (struct TagItem *)&tag );
  4109. }
  4110.  
  4111. BOOL SetMidiLinkAttrs(struct MidiLink *mi, Tag tag, ...)
  4112. {
  4113.     return SetMidiLinkAttrsA(mi, (struct TagItem *)&tag );
  4114. }
  4115.